diff --git a/core/src/consensus.rs b/core/src/consensus.rs index b14ec8d6..5500a124 100644 --- a/core/src/consensus.rs +++ b/core/src/consensus.rs @@ -84,11 +84,6 @@ pub const SECOND_POW_EDGE_BITS: u8 = 29; /// Cuckoo graph sizes, changing this would hard fork pub const BASE_EDGE_BITS: u8 = 24; -/// Maximum scaling factor for secondary pow, enforced in diff retargetting -/// increasing scaling factor increases frequency of secondary blocks -/// ONLY IN TESTNET4 LIMITED TO ABOUT 8 TIMES THE NATURAL SCALE -pub const MAX_SECONDARY_SCALING: u64 = 8 << 11; - /// Default number of blocks in the past when cross-block cut-through will start /// happening. Needs to be long enough to not overlap with a long reorg. /// Rational @@ -181,9 +176,14 @@ pub fn graph_weight(height: u64, edge_bits: u8) -> u64 { (2 << (edge_bits - global::base_edge_bits()) as u64) * xpr_edge_bits } -/// minimum difficulty to avoid getting stuck when trying to increase subject to dampening +/// Minimum difficulty, enforced in diff retargetting +/// avoids getting stuck when trying to increase difficulty subject to dampening pub const MIN_DIFFICULTY: u64 = DIFFICULTY_DAMP_FACTOR; +/// Minimum scaling factor for AR pow, enforced in diff retargetting +/// avoids getting stuck when trying to increase ar_scale subject to dampening +pub const MIN_AR_SCALE: u64 = AR_SCALE_DAMP_FACTOR; + /// unit difficulty, equal to graph_weight(SECOND_POW_EDGE_BITS) pub const UNIT_DIFFICULTY: u64 = ((2 as u64) << (SECOND_POW_EDGE_BITS - BASE_EDGE_BITS)) * (SECOND_POW_EDGE_BITS as u64); @@ -231,7 +231,7 @@ impl HeaderInfo { timestamp, difficulty, secondary_scaling: global::initial_graph_weight(), - is_secondary: false, + is_secondary: global::is_mainnet(), // floonet launched with false:-( } } @@ -280,8 +280,8 @@ where // DIFFICULTY_ADJUST_WINDOW + 1 (for initial block time bound) let diff_data = global::difficulty_data_to_vector(cursor); - // First, get the ratio of secondary PoW vs primary - let sec_pow_scaling = secondary_pow_scaling(height, &diff_data); + // First, get the ratio of secondary PoW vs primary, skipping initial header + let sec_pow_scaling = secondary_pow_scaling(height, &diff_data[1..]); // Get the timestamp delta across the window let ts_delta: u64 = @@ -306,13 +306,10 @@ where HeaderInfo::from_diff_scaling(Difficulty::from_num(difficulty), sec_pow_scaling) } -/// Count the number of "secondary" (AR) blocks in the provided window of blocks. -/// Note: we skip the first one, but testnet4 was incorrectly including it before -/// the hardfork. -fn ar_count(_height: u64, diff_data: &[HeaderInfo]) -> u64 { +/// Count, in units of 1/100 (a percent), the number of "secondary" (AR) blocks in the provided window of blocks. +pub fn ar_count(_height: u64, diff_data: &[HeaderInfo]) -> u64 { 100 * diff_data .iter() - .skip(1) .filter(|n| n.is_secondary) .count() as u64 } @@ -322,7 +319,6 @@ pub fn secondary_pow_scaling(height: u64, diff_data: &[HeaderInfo]) -> u32 { // Get the scaling factor sum of the last DIFFICULTY_ADJUST_WINDOW elements let scale_sum: u64 = diff_data .iter() - .skip(1) .map(|dd| dd.secondary_scaling as u64) .sum(); @@ -341,10 +337,10 @@ pub fn secondary_pow_scaling(height: u64, diff_data: &[HeaderInfo]) -> u32 { target_count, CLAMP_FACTOR, ); - let scale = scale_sum * target_pct / adj_count; + let scale = scale_sum * target_pct / max(1, adj_count); - // minimum difficulty avoids getting stuck due to dampening - max(MIN_DIFFICULTY, min(scale, MAX_SECONDARY_SCALING)) as u32 + // minimum AR scale avoids getting stuck due to dampening + max(MIN_AR_SCALE, scale) as u32 } #[cfg(test)] diff --git a/core/src/global.rs b/core/src/global.rs index be7db1f7..b3ba9fef 100644 --- a/core/src/global.rs +++ b/core/src/global.rs @@ -266,6 +266,12 @@ pub fn is_testnet() -> bool { ChainTypes::Floonet == *param_ref } +/// Are we for real? +pub fn is_mainnet() -> bool { + let param_ref = CHAIN_TYPE.read(); + ChainTypes::Mainnet == *param_ref +} + /// Helper function to get a nonce known to create a valid POW on /// the genesis block, to prevent it taking ages. Should be fine for now /// as the genesis block POW solution turns out to be the same for every new diff --git a/core/tests/consensus.rs b/core/tests/consensus.rs index fbb1ab2c..2cb6d2dd 100644 --- a/core/tests/consensus.rs +++ b/core/tests/consensus.rs @@ -541,118 +541,44 @@ fn test_secondary_pow_scale() { let window = DIFFICULTY_ADJUST_WINDOW; let mut hi = HeaderInfo::from_diff_scaling(Difficulty::from_num(10), 100); - // floonet testing - { - global::set_mining_mode(global::ChainTypes::Floonet); - assert_eq!(global::is_testnet(), true); - - // all primary, factor should increase so it becomes easier to find a high - // difficulty block - hi.is_secondary = false; - assert_eq!( - secondary_pow_scaling(1, &(0..window).map(|_| hi.clone()).collect::>()), - 106 - ); - // all secondary on 90%, factor should go down a bit - hi.is_secondary = true; - assert_eq!( - secondary_pow_scaling(1, &(0..window).map(|_| hi.clone()).collect::>()), - 97 - ); - // all secondary on 1%, factor should go down to bound (divide by 2) - assert_eq!( - secondary_pow_scaling( - 890_000, - &(0..window).map(|_| hi.clone()).collect::>() - ), - 67 - ); - // same as above, testing lowest bound - let mut low_hi = - HeaderInfo::from_diff_scaling(Difficulty::from_num(10), MIN_DIFFICULTY as u32); - low_hi.is_secondary = true; - assert_eq!( - secondary_pow_scaling( - 890_000, - &(0..window).map(|_| low_hi.clone()).collect::>() - ), - MIN_DIFFICULTY as u32 - ); - // just about the right ratio, also no longer playing with median - let mut primary_hi = HeaderInfo::from_diff_scaling(Difficulty::from_num(10), 50); - primary_hi.is_secondary = false; - assert_eq!( - secondary_pow_scaling( - 1, - &(0..(window / 10)) - .map(|_| primary_hi.clone()) - .chain((0..(window * 9 / 10)).map(|_| hi.clone())) - .collect::>() - ), - 94 - ); - // 95% secondary, should come down based on 97.5 average - assert_eq!( - secondary_pow_scaling( - 1, - &(0..(window / 20)) - .map(|_| primary_hi.clone()) - .chain((0..(window * 95 / 100)).map(|_| hi.clone())) - .collect::>() - ), - 96 - ); - // 40% secondary, should come up based on 70 average - assert_eq!( - secondary_pow_scaling( - 1, - &(0..(window * 6 / 10)) - .map(|_| primary_hi.clone()) - .chain((0..(window * 4 / 10)).map(|_| hi.clone())) - .collect::>() - ), - 72 - ); - } - // mainnet testing { global::set_mining_mode(global::ChainTypes::Mainnet); - assert_eq!(global::is_testnet(), false); + assert_eq!(global::is_mainnet(), true); // all primary, factor should increase so it becomes easier to find a high // difficulty block hi.is_secondary = false; assert_eq!( secondary_pow_scaling(1, &(0..window).map(|_| hi.clone()).collect::>()), - 106 + 108 ); // all secondary on 90%, factor should go down a bit hi.is_secondary = true; assert_eq!( secondary_pow_scaling(1, &(0..window).map(|_| hi.clone()).collect::>()), - 97 + 99 ); // all secondary on 1%, factor should go down to bound (divide by 2) assert_eq!( secondary_pow_scaling( - 890_000, + 2 * YEAR_HEIGHT * 83 / 90, &(0..window).map(|_| hi.clone()).collect::>() ), - 67 + 50 ); // same as above, testing lowest bound let mut low_hi = - HeaderInfo::from_diff_scaling(Difficulty::from_num(10), MIN_DIFFICULTY as u32); + HeaderInfo::from_diff_scaling(Difficulty::from_num(10), MIN_AR_SCALE as u32); low_hi.is_secondary = true; assert_eq!( secondary_pow_scaling( - 890_000, + 2 * YEAR_HEIGHT, &(0..window).map(|_| low_hi.clone()).collect::>() ), - MIN_DIFFICULTY as u32 + MIN_AR_SCALE as u32 ); - // just about the right ratio, also no longer playing with median + // the right ratio of 95% secondary let mut primary_hi = HeaderInfo::from_diff_scaling(Difficulty::from_num(10), 50); primary_hi.is_secondary = false; assert_eq!( @@ -663,7 +589,7 @@ fn test_secondary_pow_scale() { .chain((0..(window * 9 / 10)).map(|_| hi.clone())) .collect::>() ), - 94 + 95, // avg ar_scale of 10% * 50 + 90% * 100 ); // 95% secondary, should come down based on 97.5 average assert_eq!( @@ -674,7 +600,7 @@ fn test_secondary_pow_scale() { .chain((0..(window * 95 / 100)).map(|_| hi.clone())) .collect::>() ), - 96 + 97 ); // 40% secondary, should come up based on 70 average assert_eq!( @@ -685,7 +611,7 @@ fn test_secondary_pow_scale() { .chain((0..(window * 4 / 10)).map(|_| hi.clone())) .collect::>() ), - 72 + 73 ); } }