Skip to content

Commit

Permalink
Secondary PoW factor adjustment adjustments
Browse files Browse the repository at this point in the history
  • Loading branch information
ignopeverell committed Oct 15, 2018
1 parent 45a5655 commit eeb7680
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 12 deletions.
30 changes: 22 additions & 8 deletions core/src/consensus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
//! enough, consensus-relevant constants and short functions should be kept
//! here.
use std::cmp::max;
use std::cmp::{max, min};
use std::fmt;

use global;
Expand Down Expand Up @@ -293,8 +293,10 @@ where
HeaderInfo::from_diff_scaling(Difficulty::from_num(difficulty), sec_pow_scaling)
}

pub const MAX_SECONDARY_SCALING: u64 = (::std::u32::MAX / 70) as u64;

/// Factor by which the secondary proof of work difficulty will be adjusted
fn secondary_pow_scaling(height: u64, diff_data: &Vec<HeaderInfo>) -> u32 {
pub fn secondary_pow_scaling(height: u64, diff_data: &Vec<HeaderInfo>) -> u32 {
// median of past scaling factors, scaling is 1 if none found
let mut scalings = diff_data
.iter()
Expand All @@ -305,18 +307,30 @@ fn secondary_pow_scaling(height: u64, diff_data: &Vec<HeaderInfo>) -> u32 {
}
scalings.sort();
let scaling_median = scalings[scalings.len() / 2] as u64;
let secondary_count = diff_data.iter().filter(|n| n.is_secondary).count() as u64;
let secondary_count = max(diff_data.iter().filter(|n| n.is_secondary).count(), 1) as u64;

// what's the ideal ratio at the current height
let ratio = secondary_pow_ratio(height);

println!(
"-- {} {} {} {}",
scaling_median,
secondary_count,
diff_data.len(),
ratio
);
// adjust the past median based on ideal ratio vs actual ratio
let scaling = scaling_median * secondary_count * 100 / ratio / diff_data.len() as u64;
if scaling == 0 {
1
let scaling = scaling_median * diff_data.len() as u64 * ratio / 100 / secondary_count as u64;

// various bounds
let bounded_scaling = if scaling < scaling_median / 4 || scaling == 0 {
max(scaling_median / 4, 1)
} else if scaling > MAX_SECONDARY_SCALING || scaling > scaling_median * 4 {
min(MAX_SECONDARY_SCALING, scaling_median * 4)
} else {
scaling as u32
}
scaling
};
bounded_scaling as u32
}

/// Median timestamp within the time window starting at `from` with the
Expand Down
70 changes: 66 additions & 4 deletions core/tests/consensus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,7 @@ extern crate grin_core as core;
extern crate chrono;

use chrono::prelude::Utc;
use core::consensus::{
next_difficulty, valid_header_version, HeaderInfo, BLOCK_TIME_WINDOW, DAMP_FACTOR,
DIFFICULTY_ADJUST_WINDOW, MEDIAN_TIME_INDEX, MEDIAN_TIME_WINDOW, UPPER_TIME_BOUND,
};
use core::consensus::*;
use core::global;
use core::pow::Difficulty;
use std::fmt::{self, Display};
Expand Down Expand Up @@ -514,6 +511,71 @@ fn next_target_adjustment() {
);
}

#[test]
fn secondary_pow_scale() {
let window = DIFFICULTY_ADJUST_WINDOW + MEDIAN_TIME_WINDOW;
let mut hi = HeaderInfo::from_diff_scaling(Difficulty::from_num(10), 100);

// all primary, factor should be multiplied by 4 (max adjustment) so it
// becomes easier to find a high difficulty block
assert_eq!(
secondary_pow_scaling(1, &(0..window).map(|_| hi.clone()).collect()),
400
);
// all secondary on 90%, factor should lose 10%
hi.is_secondary = true;
assert_eq!(
secondary_pow_scaling(1, &(0..window).map(|_| hi.clone()).collect()),
90
);
// all secondary on 1%, should be divided by 4 (max adjustment)
assert_eq!(
secondary_pow_scaling(890_000, &(0..window).map(|_| hi.clone()).collect()),
25
);
// same as above, testing lowest bound
let mut low_hi = HeaderInfo::from_diff_scaling(Difficulty::from_num(10), 3);
low_hi.is_secondary = true;
assert_eq!(
secondary_pow_scaling(890_000, &(0..window).map(|_| low_hi.clone()).collect()),
1
);
// just about the right ratio, also playing with median
let primary_hi = HeaderInfo::from_diff_scaling(Difficulty::from_num(10), 50);
assert_eq!(
secondary_pow_scaling(
1,
&(0..(window / 10))
.map(|_| primary_hi.clone())
.chain((0..(window * 9 / 10)).map(|_| hi.clone()))
.collect()
),
100
);
// 95% secondary, should come down
assert_eq!(
secondary_pow_scaling(
1,
&(0..(window / 20))
.map(|_| primary_hi.clone())
.chain((0..(window * 95 / 100)).map(|_| hi.clone()))
.collect()
),
94
);
// 40% secondary, should come up
assert_eq!(
secondary_pow_scaling(
1,
&(0..(window * 6 / 10))
.map(|_| primary_hi.clone())
.chain((0..(window * 4 / 10)).map(|_| hi.clone()))
.collect()
),
112
);
}

#[test]
fn hard_forks() {
assert!(valid_header_version(0, 1));
Expand Down

0 comments on commit eeb7680

Please sign in to comment.