mirror of
https://github.com/mimblewimble/grin.git
synced 2025-01-21 11:31:08 +03:00
a1b6c31481
* tests: split consensus tests into separate files for each chain type to avoid non deterministic behaviour due to shared global state in global.rs
158 lines
4.8 KiB
Rust
158 lines
4.8 KiB
Rust
// Copyright 2020 The Grin Developers
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
use chrono::Utc;
|
|
use grin_core::consensus::{
|
|
next_difficulty, HeaderInfo, AR_SCALE_DAMP_FACTOR, BLOCK_TIME_SEC, DIFFICULTY_ADJUST_WINDOW,
|
|
MIN_DIFFICULTY,
|
|
};
|
|
use grin_core::global;
|
|
use grin_core::pow::Difficulty;
|
|
|
|
/// Checks different next_target adjustments and difficulty boundaries
|
|
#[test]
|
|
fn next_target_adjustment() {
|
|
global::set_mining_mode(global::ChainTypes::AutomatedTesting);
|
|
let cur_time = Utc::now().timestamp() as u64;
|
|
let diff_min = Difficulty::min();
|
|
|
|
// Check we don't get stuck on difficulty <= MIN_DIFFICULTY (at 4x faster blocks at least)
|
|
let mut hi = HeaderInfo::from_diff_scaling(diff_min, AR_SCALE_DAMP_FACTOR as u32);
|
|
hi.is_secondary = false;
|
|
let hinext = next_difficulty(
|
|
1,
|
|
repeat(
|
|
BLOCK_TIME_SEC / 4,
|
|
hi.clone(),
|
|
DIFFICULTY_ADJUST_WINDOW,
|
|
None,
|
|
),
|
|
);
|
|
|
|
assert_ne!(hinext.difficulty, diff_min);
|
|
|
|
// Check we don't get stuck on scale MIN_DIFFICULTY, when primary frequency is too high
|
|
assert_ne!(hinext.secondary_scaling, MIN_DIFFICULTY as u32);
|
|
|
|
// just enough data, right interval, should stay constant
|
|
let just_enough = DIFFICULTY_ADJUST_WINDOW + 1;
|
|
hi.difficulty = Difficulty::from_num(10000);
|
|
assert_eq!(
|
|
next_difficulty(1, repeat(BLOCK_TIME_SEC, hi.clone(), just_enough, None)).difficulty,
|
|
Difficulty::from_num(10000)
|
|
);
|
|
|
|
// check pre difficulty_data_to_vector effect on retargetting
|
|
assert_eq!(
|
|
next_difficulty(1, vec![HeaderInfo::from_ts_diff(42, hi.difficulty)]).difficulty,
|
|
Difficulty::from_num(14913)
|
|
);
|
|
|
|
// checking averaging works
|
|
hi.difficulty = Difficulty::from_num(500);
|
|
let sec = DIFFICULTY_ADJUST_WINDOW / 2;
|
|
let mut s1 = repeat(BLOCK_TIME_SEC, hi.clone(), sec, Some(cur_time));
|
|
let mut s2 = repeat_offs(
|
|
cur_time + (sec * BLOCK_TIME_SEC) as u64,
|
|
BLOCK_TIME_SEC,
|
|
1500,
|
|
DIFFICULTY_ADJUST_WINDOW / 2,
|
|
);
|
|
s2.append(&mut s1);
|
|
assert_eq!(
|
|
next_difficulty(1, s2).difficulty,
|
|
Difficulty::from_num(1000)
|
|
);
|
|
|
|
// too slow, diff goes down
|
|
hi.difficulty = Difficulty::from_num(1000);
|
|
assert_eq!(
|
|
next_difficulty(1, repeat(90, hi.clone(), just_enough, None)).difficulty,
|
|
Difficulty::from_num(857)
|
|
);
|
|
assert_eq!(
|
|
next_difficulty(1, repeat(120, hi.clone(), just_enough, None)).difficulty,
|
|
Difficulty::from_num(750)
|
|
);
|
|
|
|
// too fast, diff goes up
|
|
assert_eq!(
|
|
next_difficulty(1, repeat(55, hi.clone(), just_enough, None)).difficulty,
|
|
Difficulty::from_num(1028)
|
|
);
|
|
assert_eq!(
|
|
next_difficulty(1, repeat(45, hi.clone(), just_enough, None)).difficulty,
|
|
Difficulty::from_num(1090)
|
|
);
|
|
assert_eq!(
|
|
next_difficulty(1, repeat(30, hi.clone(), just_enough, None)).difficulty,
|
|
Difficulty::from_num(1200)
|
|
);
|
|
|
|
// hitting lower time bound, should always get the same result below
|
|
assert_eq!(
|
|
next_difficulty(1, repeat(0, hi.clone(), just_enough, None)).difficulty,
|
|
Difficulty::from_num(1500)
|
|
);
|
|
|
|
// hitting higher time bound, should always get the same result above
|
|
assert_eq!(
|
|
next_difficulty(1, repeat(300, hi.clone(), just_enough, None)).difficulty,
|
|
Difficulty::from_num(500)
|
|
);
|
|
assert_eq!(
|
|
next_difficulty(1, repeat(400, hi.clone(), just_enough, None)).difficulty,
|
|
Difficulty::from_num(500)
|
|
);
|
|
|
|
// We should never drop below minimum
|
|
hi.difficulty = Difficulty::zero();
|
|
assert_eq!(
|
|
next_difficulty(1, repeat(90, hi.clone(), just_enough, None)).difficulty,
|
|
Difficulty::min()
|
|
);
|
|
}
|
|
|
|
// Builds an iterator for next difficulty calculation with the provided
|
|
// constant time interval, difficulty and total length.
|
|
fn repeat(interval: u64, diff: HeaderInfo, len: u64, cur_time: Option<u64>) -> Vec<HeaderInfo> {
|
|
let cur_time = match cur_time {
|
|
Some(t) => t,
|
|
None => Utc::now().timestamp() as u64,
|
|
};
|
|
// watch overflow here, length shouldn't be ridiculous anyhow
|
|
assert!(len < std::usize::MAX as u64);
|
|
let diffs = vec![diff.difficulty.clone(); len as usize];
|
|
let times = (0..(len as usize)).map(|n| n * interval as usize).rev();
|
|
let pairs = times.zip(diffs.iter());
|
|
pairs
|
|
.map(|(t, d)| {
|
|
HeaderInfo::new(
|
|
diff.block_hash,
|
|
cur_time + t as u64,
|
|
d.clone(),
|
|
diff.secondary_scaling,
|
|
diff.is_secondary,
|
|
)
|
|
})
|
|
.collect::<Vec<_>>()
|
|
}
|
|
|
|
fn repeat_offs(from: u64, interval: u64, diff: u64, len: u64) -> Vec<HeaderInfo> {
|
|
repeat(
|
|
interval,
|
|
HeaderInfo::from_ts_diff(1, Difficulty::from_num(diff)),
|
|
len,
|
|
Some(from),
|
|
)
|
|
}
|