Skip to content

Commit

Permalink
Track blocks that are produced by validator
Browse files Browse the repository at this point in the history
Track the number of blocks that are succesfully produced when changing the validator health
  • Loading branch information
viquezclaudio committed Dec 26, 2024
1 parent b5198c5 commit 124258f
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 25 deletions.
21 changes: 13 additions & 8 deletions validator/src/micro.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ use nimiq_validator_network::ValidatorNetwork;
use nimiq_vrf::VrfSeed;
use parking_lot::RwLock;

use crate::{aggregation::skip_block::SkipBlockAggregation, validator::Validator};
use crate::{
aggregation::skip_block::SkipBlockAggregation,
validator::{HealthState, Validator},
};

pub(crate) enum ProduceMicroBlockEvent {
MicroBlock,
Expand All @@ -38,7 +41,7 @@ struct NextProduceMicroBlockEvent<TValidatorNetwork> {
producer_timeout: Duration,
block_separation_time: Duration,
validator_address: Address,
publish_block: bool,
health_state: Arc<RwLock<HealthState>>,
}

impl<TValidatorNetwork: ValidatorNetwork + 'static> NextProduceMicroBlockEvent<TValidatorNetwork> {
Expand All @@ -57,7 +60,7 @@ impl<TValidatorNetwork: ValidatorNetwork + 'static> NextProduceMicroBlockEvent<T
producer_timeout: Duration,
block_separation_time: Duration,
validator_address: Address,
publish_block: bool,
health_state: Arc<RwLock<HealthState>>,
) -> Self {
Self {
blockchain,
Expand All @@ -71,7 +74,7 @@ impl<TValidatorNetwork: ValidatorNetwork + 'static> NextProduceMicroBlockEvent<T
producer_timeout,
block_separation_time,
validator_address,
publish_block,
health_state,
}
}

Expand Down Expand Up @@ -161,8 +164,8 @@ impl<TValidatorNetwork: ValidatorNetwork + 'static> NextProduceMicroBlockEvent<T
num_transactions
);

if !self.publish_block {
log::warn!("Not publishing block {} ", block.block_number());
if !self.health_state.read().publish {
log::warn!(block = block.block_number(), "Not publishing block");
let event = ProduceMicroBlockEvent::MicroBlock;
break Some(Some(event));
}
Expand Down Expand Up @@ -195,6 +198,8 @@ impl<TValidatorNetwork: ValidatorNetwork + 'static> NextProduceMicroBlockEvent<T
continue;
}

self.health_state.write().blk_cnt += 1;

let event = result
.map(move |_result| ProduceMicroBlockEvent::MicroBlock)
.ok();
Expand Down Expand Up @@ -420,7 +425,7 @@ impl<TValidatorNetwork: ValidatorNetwork + 'static> ProduceMicroBlock<TValidator
producer_timeout: Duration,
block_separation_time: Duration,
validator_address: Address,
publish_block: bool,
health_state: Arc<RwLock<HealthState>>,
) -> Self {
let next_event = NextProduceMicroBlockEvent::new(
blockchain,
Expand All @@ -434,7 +439,7 @@ impl<TValidatorNetwork: ValidatorNetwork + 'static> ProduceMicroBlock<TValidator
producer_timeout,
block_separation_time,
validator_address,
publish_block,
health_state,
)
.next()
.boxed();
Expand Down
39 changes: 24 additions & 15 deletions validator/src/validator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ use crate::{
r#macro::{MappedReturn, ProduceMacroBlock, ProposalTopic},
};

/// The number of blocks a validator needs to produce in time to improve its health
const VALIDATOR_HEALTH_THRESHOLD: u32 = 5;

#[derive(PartialEq)]
enum ValidatorStakingState {
Active,
Expand Down Expand Up @@ -80,6 +83,8 @@ pub enum ValidatorHealth {
pub struct HealthState {
/// The current validator health
pub health: ValidatorHealth,
/// Number of blocks that we have produced in time(without being inactivated)
pub blk_cnt: u32,
/// For testing/debug purposes control wether produced blocks are published by the validator
pub publish: bool,
}
Expand Down Expand Up @@ -229,6 +234,7 @@ where
let health_state = HealthState {
health: ValidatorHealth::Green,
publish: true,
blk_cnt: 0,
};

Self {
Expand Down Expand Up @@ -482,7 +488,7 @@ where
Self::compute_micro_block_producer_timeout(head, &blockchain),
Self::BLOCK_SEPARATION_TIME,
self.validator_address.read().clone(),
self.health_state.read().publish,
Arc::clone(&self.health_state),
));
}
}
Expand Down Expand Up @@ -882,28 +888,29 @@ where
match validator_health {
ValidatorHealth::Green => {}
ValidatorHealth::Yellow(yellow_block_number) => {
let blocks_diff = block_number - yellow_block_number;
debug!(
"Current validator health {} is yellow, blocks diff: {} ",
self.validator_address.read(),
blocks_diff
address = %self.validator_address.read(),
inactivated = yellow_block_number,
good_blocks = %self.health_state.read().blk_cnt,
"Current validator health is yellow",
);
if blocks_diff >= Policy::blocks_per_epoch() / 4 {
if self.health_state.read().blk_cnt >= VALIDATOR_HEALTH_THRESHOLD {
log::info!("Changing the validator health back to green");
self.health_state.write().health = ValidatorHealth::Green;
self.health_state.write().blk_cnt = 0;
}
}
ValidatorHealth::Red(red_block_number) => {
let blocks_diff = block_number - red_block_number;
debug!(
"Current validator health {} is red, blocks diff: {} ",
self.validator_address.read(),
blocks_diff
address = %self.validator_address.read(),
inactivated = red_block_number,
"Current validator health is red",
);
if blocks_diff >= Policy::blocks_per_epoch() / 4 {
if self.health_state.read().blk_cnt >= VALIDATOR_HEALTH_THRESHOLD {
log::info!("Changing the validator health back to yellow");
self.health_state.write().health =
ValidatorHealth::Yellow(block_number);
self.health_state.write().blk_cnt = 0;
}
}
}
Expand All @@ -921,25 +928,27 @@ where
match validator_health {
ValidatorHealth::Green => {
log::warn!(
"The validator {} was inactivated, changing its health to Yellow",
self.validator_address.read()
address=%self.validator_address.read(),
"The validator was inactivated, changing its health to Yellow",
);
let inactivity_state = self.reactivate(&blockchain);
drop(blockchain);
self.validator_state = Some(inactivity_state);
self.health_state.write().health =
ValidatorHealth::Yellow(block_number);
self.health_state.write().blk_cnt = 0;
}
ValidatorHealth::Yellow(_) => {
log::warn!(
"The validator {} was inactivated again, changing its health to Red",
self.validator_address.read()
address=%self.validator_address.read(),
"The validator was inactivated again, changing its health to Red",
);
let inactivity_state = self.reactivate(&blockchain);
drop(blockchain);
self.validator_state = Some(inactivity_state);
self.health_state.write().health =
ValidatorHealth::Red(block_number);
self.health_state.write().blk_cnt = 0;
}
ValidatorHealth::Red(_) => {
log::warn!(
Expand Down
4 changes: 2 additions & 2 deletions validator/tests/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ async fn validator_can_recover_from_yellow_health() {
validator_proxy.validator_health.write().publish = true;

let events = blockchain.read().notifier_as_stream();
events.take(30).for_each(|_| future::ready(())).await;
events.take(40).for_each(|_| future::ready(())).await;

assert_eq!(
validator_proxy.validator_health.read().health,
Expand Down Expand Up @@ -372,7 +372,7 @@ async fn validator_health_fully_recover() {
validator_proxy.validator_health.write().publish = true;

let events = blockchain.read().notifier_as_stream();
events.take(70).for_each(|_| future::ready(())).await;
events.take(100).for_each(|_| future::ready(())).await;

let current_validator_health = validator_proxy.validator_health.read().health;

Expand Down

0 comments on commit 124258f

Please sign in to comment.