Skip to content

Commit

Permalink
Merge #4359
Browse files Browse the repository at this point in the history
4359: Add tests for Highway exponent switching r=AlexanderLimonov a=fizyk20

Closes #4306 


Co-authored-by: Bartłomiej Kamiński <bart@casperlabs.io>
  • Loading branch information
casperlabs-bors-ng[bot] and fizyk20 authored Oct 27, 2023
2 parents 6756c47 + a85d06c commit 6afe56b
Show file tree
Hide file tree
Showing 9 changed files with 758 additions and 123 deletions.
8 changes: 4 additions & 4 deletions execution_engine/src/storage/trie_store/operations/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -594,10 +594,10 @@ where
new_elements.push((trie_key, new_extension))
}
// The single sibling is an extension. We output an extension to
// replace the parent, prepending the
// sibling index to the sibling's affix. In
// the next loop iteration, we will handle the case where this extension
// might need to be combined with a grandparent extension.
// replace the parent, prepending the sibling index to the sibling's
// affix. In the next loop iteration, we will handle the case where
// this extension might need to be combined with a grandparent
// extension.
Trie::Extension {
affix: extension_affix,
pointer,
Expand Down
1 change: 1 addition & 0 deletions node/src/components/consensus/cl_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use crate::{
};

#[derive(DataSize)]
#[cfg_attr(test, derive(Clone))]
pub struct Keypair {
secret_key: Arc<SecretKey>,
public_key: PublicKey,
Expand Down
10 changes: 10 additions & 0 deletions node/src/components/consensus/highway_core/highway.rs
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,16 @@ impl<C: Context> Highway<C> {
self.active_validator = None;
}

/// Gets the round exponent for the next message this instance will create.
#[cfg(test)]
#[allow(clippy::integer_arithmetic)]
pub(crate) fn get_round_exp(&self) -> Option<u8> {
self.active_validator.as_ref().map(|av| {
(av.next_round_length().millis() / self.state.params().min_round_length().millis())
.trailing_zeros() as u8
})
}

/// Switches the active validator to a new round length.
pub(crate) fn set_round_len(&mut self, new_round_len: TimeDiff) {
if let Some(ref mut av) = self.active_validator {
Expand Down
2 changes: 1 addition & 1 deletion node/src/components/consensus/protocols/highway.rs
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,7 @@ impl<C: Context + 'static> HighwayProtocol<C> {
fn calculate_round_length(&mut self, vv: &ValidVertex<C>, now: Timestamp) {
let new_round_len = self
.round_success_meter
.calculate_new_length(self.highway.state());
.calculate_new_length(self.highway.state(), now);
// If the vertex contains a proposal, register it in the success meter.
// It's important to do this _after_ the calculation above - otherwise we might try to
// register the proposal before the meter is aware that a new round has started, and it
Expand Down
120 changes: 4 additions & 116 deletions node/src/components/consensus/protocols/highway/round_success_meter.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
#[cfg(test)]
mod tests;

use std::{cmp::max, collections::VecDeque, mem};

use datasize::DataSize;
Expand Down Expand Up @@ -102,8 +105,7 @@ impl<C: Context> RoundSuccessMeter<C> {
/// successful, we return a higher round length for the future.
/// If the length shouldn't grow, and the round ID is divisible by a certain number, a lower
/// round length is returned.
pub fn calculate_new_length(&mut self, state: &State<C>) -> TimeDiff {
let now = Timestamp::now();
pub fn calculate_new_length(&mut self, state: &State<C>, now: Timestamp) -> TimeDiff {
// if the round hasn't finished, just return whatever we have now
if state::round_id(now, self.current_round_len) <= self.current_round_id {
return self.new_length();
Expand Down Expand Up @@ -212,117 +214,3 @@ fn round_index(r_id: Timestamp, round_len: TimeDiff) -> u64 {
}
r_id.millis() / round_len.millis()
}

#[cfg(test)]
mod tests {
use config::{Config, ACCELERATION_PARAMETER, MAX_FAILED_ROUNDS, NUM_ROUNDS_TO_CONSIDER};

use casper_types::{TimeDiff, Timestamp};

use crate::components::consensus::{
cl_context::ClContext,
protocols::highway::round_success_meter::{config, round_index},
};

const TEST_ROUND_LEN: TimeDiff = TimeDiff::from_millis(1 << 13);
const TEST_MIN_ROUND_LEN: TimeDiff = TimeDiff::from_millis(1 << 8);
const TEST_MAX_ROUND_LEN: TimeDiff = TimeDiff::from_millis(1 << 19);

#[test]
fn new_length_steady() {
let round_success_meter: super::RoundSuccessMeter<ClContext> =
super::RoundSuccessMeter::new(
TEST_ROUND_LEN,
TEST_MIN_ROUND_LEN,
TEST_MAX_ROUND_LEN,
Timestamp::now(),
Config::default(),
);
assert_eq!(round_success_meter.new_length(), TEST_ROUND_LEN);
}

#[test]
fn new_length_slow_down() {
let mut round_success_meter: super::RoundSuccessMeter<ClContext> =
super::RoundSuccessMeter::new(
TEST_ROUND_LEN,
TEST_MIN_ROUND_LEN,
TEST_MAX_ROUND_LEN,
Timestamp::now(),
Config::default(),
);
// If there have been more rounds of failure than MAX_FAILED_ROUNDS, slow down
round_success_meter.rounds = vec![false; MAX_FAILED_ROUNDS + 1].into();
assert_eq!(round_success_meter.new_length(), TEST_ROUND_LEN * 2);
}

#[test]
fn new_length_can_not_slow_down_because_max_round_len() {
// If the round length is the same as the maximum round length, can't go up
let mut round_success_meter: super::RoundSuccessMeter<ClContext> =
super::RoundSuccessMeter::new(
TEST_MAX_ROUND_LEN,
TEST_MIN_ROUND_LEN,
TEST_MAX_ROUND_LEN,
Timestamp::now(),
Config::default(),
);
// If there have been more rounds of failure than MAX_FAILED_ROUNDS, slow down -- but can't
// slow down because of ceiling
round_success_meter.rounds = vec![false; MAX_FAILED_ROUNDS + 1].into();
assert_eq!(round_success_meter.new_length(), TEST_MAX_ROUND_LEN);
}

#[test]
fn new_length_speed_up() {
// If there's been enough successful rounds and it's an acceleration round, speed up
let mut round_success_meter: super::RoundSuccessMeter<ClContext> =
super::RoundSuccessMeter::new(
TEST_ROUND_LEN,
TEST_MIN_ROUND_LEN,
TEST_MAX_ROUND_LEN,
Timestamp::now(),
Config::default(),
);
round_success_meter.rounds = vec![true; NUM_ROUNDS_TO_CONSIDER].into();
// Increase our round index until we are at an acceleration round
loop {
let current_round_index = round_index(
round_success_meter.current_round_id,
round_success_meter.current_round_len,
);
if current_round_index % ACCELERATION_PARAMETER == 0 {
break;
};
round_success_meter.current_round_id += TimeDiff::from_millis(1);
}
assert_eq!(round_success_meter.new_length(), TEST_ROUND_LEN / 2);
}

#[test]
fn new_length_can_not_speed_up_because_min_round_len() {
// If there's been enough successful rounds and it's an acceleration round, but we are
// already at the smallest round length possible, stay at the current round length
let mut round_success_meter: super::RoundSuccessMeter<ClContext> =
super::RoundSuccessMeter::new(
TEST_MIN_ROUND_LEN,
TEST_MIN_ROUND_LEN,
TEST_MAX_ROUND_LEN,
Timestamp::now(),
Config::default(),
);
round_success_meter.rounds = vec![true; NUM_ROUNDS_TO_CONSIDER].into();
// Increase our round index until we are at an acceleration round
loop {
let current_round_index = round_index(
round_success_meter.current_round_id,
round_success_meter.current_round_len,
);
if current_round_index % ACCELERATION_PARAMETER == 0 {
break;
};
round_success_meter.current_round_id += TimeDiff::from_millis(1);
}
assert_eq!(round_success_meter.new_length(), TEST_MIN_ROUND_LEN);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
use config::{Config, ACCELERATION_PARAMETER, MAX_FAILED_ROUNDS, NUM_ROUNDS_TO_CONSIDER};

use casper_types::{TimeDiff, Timestamp};

use crate::components::consensus::{
cl_context::ClContext,
protocols::highway::round_success_meter::{config, round_index},
};

const TEST_ROUND_LEN: TimeDiff = TimeDiff::from_millis(1 << 13);
const TEST_MIN_ROUND_LEN: TimeDiff = TimeDiff::from_millis(1 << 8);
const TEST_MAX_ROUND_LEN: TimeDiff = TimeDiff::from_millis(1 << 19);

#[test]
fn new_length_steady() {
let round_success_meter: super::RoundSuccessMeter<ClContext> = super::RoundSuccessMeter::new(
TEST_ROUND_LEN,
TEST_MIN_ROUND_LEN,
TEST_MAX_ROUND_LEN,
Timestamp::now(),
Config::default(),
);
assert_eq!(round_success_meter.new_length(), TEST_ROUND_LEN);
}

#[test]
fn new_length_slow_down() {
let mut round_success_meter: super::RoundSuccessMeter<ClContext> =
super::RoundSuccessMeter::new(
TEST_ROUND_LEN,
TEST_MIN_ROUND_LEN,
TEST_MAX_ROUND_LEN,
Timestamp::now(),
Config::default(),
);
// If there have been more rounds of failure than MAX_FAILED_ROUNDS, slow down
round_success_meter.rounds = vec![false; MAX_FAILED_ROUNDS + 1].into();
assert_eq!(round_success_meter.new_length(), TEST_ROUND_LEN * 2);
}

#[test]
fn new_length_can_not_slow_down_because_max_round_len() {
// If the round length is the same as the maximum round length, can't go up
let mut round_success_meter: super::RoundSuccessMeter<ClContext> =
super::RoundSuccessMeter::new(
TEST_MAX_ROUND_LEN,
TEST_MIN_ROUND_LEN,
TEST_MAX_ROUND_LEN,
Timestamp::now(),
Config::default(),
);
// If there have been more rounds of failure than MAX_FAILED_ROUNDS, slow down -- but can't
// slow down because of ceiling
round_success_meter.rounds = vec![false; MAX_FAILED_ROUNDS + 1].into();
assert_eq!(round_success_meter.new_length(), TEST_MAX_ROUND_LEN);
}

#[test]
fn new_length_speed_up() {
// If there's been enough successful rounds and it's an acceleration round, speed up
let mut round_success_meter: super::RoundSuccessMeter<ClContext> =
super::RoundSuccessMeter::new(
TEST_ROUND_LEN,
TEST_MIN_ROUND_LEN,
TEST_MAX_ROUND_LEN,
Timestamp::now(),
Config::default(),
);
round_success_meter.rounds = vec![true; NUM_ROUNDS_TO_CONSIDER].into();
// Increase our round index until we are at an acceleration round
loop {
let current_round_index = round_index(
round_success_meter.current_round_id,
round_success_meter.current_round_len,
);
if current_round_index % ACCELERATION_PARAMETER == 0 {
break;
};
round_success_meter.current_round_id += TimeDiff::from_millis(1);
}
assert_eq!(round_success_meter.new_length(), TEST_ROUND_LEN / 2);
}

#[test]
fn new_length_can_not_speed_up_because_min_round_len() {
// If there's been enough successful rounds and it's an acceleration round, but we are
// already at the smallest round length possible, stay at the current round length
let mut round_success_meter: super::RoundSuccessMeter<ClContext> =
super::RoundSuccessMeter::new(
TEST_MIN_ROUND_LEN,
TEST_MIN_ROUND_LEN,
TEST_MAX_ROUND_LEN,
Timestamp::now(),
Config::default(),
);
round_success_meter.rounds = vec![true; NUM_ROUNDS_TO_CONSIDER].into();
// Increase our round index until we are at an acceleration round
loop {
let current_round_index = round_index(
round_success_meter.current_round_id,
round_success_meter.current_round_len,
);
if current_round_index % ACCELERATION_PARAMETER == 0 {
break;
};
round_success_meter.current_round_id += TimeDiff::from_millis(1);
}
assert_eq!(round_success_meter.new_length(), TEST_MIN_ROUND_LEN);
}
Loading

0 comments on commit 6afe56b

Please sign in to comment.