From 28e0d97e64ac150e8abf3d03aaf8c10ff30859c1 Mon Sep 17 00:00:00 2001 From: Ignotus Peverell Date: Wed, 28 Nov 2018 14:05:55 -0800 Subject: [PATCH] Cuckatoo size shift upgrade schedule (#2024) * Cuckatoo size shift upgrade schedule * Move the schedule into graph_weight instead of messing with min edge bits * Cleanup and fixes now that we have an agreed upon schedule --- chain/src/pipe.rs | 2 +- core/src/consensus.rs | 56 +++++++++++++++++++++++++++-- core/src/global.rs | 4 +-- core/src/pow/mod.rs | 4 +-- core/src/pow/types.rs | 8 ++--- servers/src/common/stats.rs | 5 +-- servers/src/mining/stratumserver.rs | 2 +- servers/src/mining/test_miner.rs | 2 +- src/bin/tui/mining.rs | 2 +- 9 files changed, 69 insertions(+), 16 deletions(-) diff --git a/chain/src/pipe.rs b/chain/src/pipe.rs index 47f8e5d6..72dee13d 100644 --- a/chain/src/pipe.rs +++ b/chain/src/pipe.rs @@ -394,7 +394,7 @@ fn validate_header(header: &BlockHeader, ctx: &mut BlockContext) -> Result<(), E let target_difficulty = header.total_difficulty() - prev.total_difficulty(); - if header.pow.to_difficulty() < target_difficulty { + if header.pow.to_difficulty(header.height) < target_difficulty { return Err(ErrorKind::DifficultyTooLow.into()); } diff --git a/core/src/consensus.rs b/core/src/consensus.rs index 6d011fef..3f1ca82b 100644 --- a/core/src/consensus.rs +++ b/core/src/consensus.rs @@ -175,8 +175,16 @@ pub const DAMP_FACTOR: u64 = 3; /// Compute weight of a graph as number of siphash bits defining the graph /// Must be made dependent on height to phase out smaller size over the years /// This can wait until end of 2019 at latest -pub fn graph_weight(edge_bits: u8) -> u64 { - (2 << (edge_bits - global::base_edge_bits()) as u64) * (edge_bits as u64) +pub fn graph_weight(height: u64, edge_bits: u8) -> u64 { + let mut xpr_edge_bits = edge_bits as u64; + + let bits_over_min = edge_bits - global::min_edge_bits(); + let expiry_height = (1 << bits_over_min) * YEAR_HEIGHT; + if height >= expiry_height { + xpr_edge_bits = xpr_edge_bits.saturating_sub(1 + (height - expiry_height) / WEEK_HEIGHT); + } + + (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 @@ -350,3 +358,47 @@ pub trait VerifySortOrder { /// Verify a collection of items is sorted as required. fn verify_sort_order(&self) -> Result<(), Error>; } + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_graph_weight() { + // initial weights + assert_eq!(graph_weight(1, 31), 256 * 31); + assert_eq!(graph_weight(1, 32), 512 * 32); + assert_eq!(graph_weight(1, 33), 1024 * 33); + + // one year in, 31 starts going down, the rest stays the same + assert_eq!(graph_weight(YEAR_HEIGHT, 31), 256 * 30); + assert_eq!(graph_weight(YEAR_HEIGHT, 32), 512 * 32); + assert_eq!(graph_weight(YEAR_HEIGHT, 33), 1024 * 33); + + // 31 loses one factor per week + assert_eq!(graph_weight(YEAR_HEIGHT + WEEK_HEIGHT, 31), 256 * 29); + assert_eq!(graph_weight(YEAR_HEIGHT + 2 * WEEK_HEIGHT, 31), 256 * 28); + assert_eq!(graph_weight(YEAR_HEIGHT + 32 * WEEK_HEIGHT, 31), 0); + + // 2 years in, 31 still at 0, 32 starts decreasing + assert_eq!(graph_weight(2 * YEAR_HEIGHT, 31), 0); + assert_eq!(graph_weight(2 * YEAR_HEIGHT, 32), 512 * 31); + assert_eq!(graph_weight(2 * YEAR_HEIGHT, 33), 1024 * 33); + + // 32 loses one factor per week + assert_eq!(graph_weight(2 * YEAR_HEIGHT + WEEK_HEIGHT, 32), 512 * 30); + assert_eq!(graph_weight(2 * YEAR_HEIGHT + WEEK_HEIGHT, 31), 0); + assert_eq!(graph_weight(2 * YEAR_HEIGHT + 30 * WEEK_HEIGHT, 32), 512); + assert_eq!(graph_weight(2 * YEAR_HEIGHT + 31 * WEEK_HEIGHT, 32), 0); + + // 3 years in, nothing changes + assert_eq!(graph_weight(3 * YEAR_HEIGHT, 31), 0); + assert_eq!(graph_weight(3 * YEAR_HEIGHT, 32), 0); + assert_eq!(graph_weight(3 * YEAR_HEIGHT, 33), 1024 * 33); + + // 4 years in, 33 starts starts decreasing + assert_eq!(graph_weight(4 * YEAR_HEIGHT, 31), 0); + assert_eq!(graph_weight(4 * YEAR_HEIGHT, 32), 0); + assert_eq!(graph_weight(4 * YEAR_HEIGHT, 33), 1024 * 32); + } +} diff --git a/core/src/global.rs b/core/src/global.rs index fe2c52b6..239a8b87 100644 --- a/core/src/global.rs +++ b/core/src/global.rs @@ -247,8 +247,8 @@ pub fn initial_graph_weight() -> u32 { ChainTypes::Testnet1 => TESTING_INITIAL_GRAPH_WEIGHT, ChainTypes::Testnet2 => TESTING_INITIAL_GRAPH_WEIGHT, ChainTypes::Testnet3 => TESTING_INITIAL_GRAPH_WEIGHT, - ChainTypes::Testnet4 => graph_weight(SECOND_POW_EDGE_BITS) as u32, - ChainTypes::Mainnet => graph_weight(SECOND_POW_EDGE_BITS) as u32, + ChainTypes::Testnet4 => graph_weight(0, SECOND_POW_EDGE_BITS) as u32, + ChainTypes::Mainnet => graph_weight(0, SECOND_POW_EDGE_BITS) as u32, } } diff --git a/core/src/pow/mod.rs b/core/src/pow/mod.rs index 24fea42d..c4498655 100644 --- a/core/src/pow/mod.rs +++ b/core/src/pow/mod.rs @@ -114,7 +114,7 @@ pub fn pow_size( ctx.set_header_nonce(bh.pre_pow(), None, true)?; if let Ok(proofs) = ctx.find_cycles() { bh.pow.proof = proofs[0].clone(); - if bh.pow.to_difficulty() >= diff { + if bh.pow.to_difficulty(bh.height) >= diff { return Ok(()); } } @@ -153,7 +153,7 @@ mod test { global::min_edge_bits(), ).unwrap(); assert_ne!(b.header.pow.nonce, 310); - assert!(b.header.pow.to_difficulty() >= Difficulty::min()); + assert!(b.header.pow.to_difficulty(0) >= Difficulty::min()); assert!(verify_size(&b.header).is_ok()); } } diff --git a/core/src/pow/types.rs b/core/src/pow/types.rs index 2a38dea1..8c2625af 100644 --- a/core/src/pow/types.rs +++ b/core/src/pow/types.rs @@ -85,9 +85,9 @@ impl Difficulty { /// Computes the difficulty from a hash. Divides the maximum target by the /// provided hash and applies the Cuck(at)oo size adjustment factor (see /// https://lists.launchpad.net/mimblewimble/msg00494.html). - fn from_proof_adjusted(proof: &Proof) -> Difficulty { + fn from_proof_adjusted(height: u64, proof: &Proof) -> Difficulty { // scale with natural scaling factor - Difficulty::from_num(proof.scaled_difficulty(graph_weight(proof.edge_bits))) + Difficulty::from_num(proof.scaled_difficulty(graph_weight(height, proof.edge_bits))) } /// Same as `from_proof_adjusted` but instead of an adjustment based on @@ -276,13 +276,13 @@ impl ProofOfWork { } /// Maximum difficulty this proof of work can achieve - pub fn to_difficulty(&self) -> Difficulty { + pub fn to_difficulty(&self, height: u64) -> Difficulty { // 2 proof of works, Cuckoo29 (for now) and Cuckoo30+, which are scaled // differently (scaling not controlled for now) if self.proof.edge_bits == SECOND_POW_EDGE_BITS { Difficulty::from_proof_scaled(&self.proof, self.secondary_scaling) } else { - Difficulty::from_proof_adjusted(&self.proof) + Difficulty::from_proof_adjusted(height, &self.proof) } } diff --git a/servers/src/common/stats.rs b/servers/src/common/stats.rs index 08cc828e..0a8c9084 100644 --- a/servers/src/common/stats.rs +++ b/servers/src/common/stats.rs @@ -159,8 +159,9 @@ pub struct PeerStats { impl StratumStats { /// Calculate network hashrate - pub fn network_hashrate(&self) -> f64 { - 42.0 * (self.network_difficulty as f64 / graph_weight(self.edge_bits as u8) as f64) / 60.0 + pub fn network_hashrate(&self, height: u64) -> f64 { + 42.0 * (self.network_difficulty as f64 / graph_weight(height, self.edge_bits as u8) as f64) + / 60.0 } } diff --git a/servers/src/mining/stratumserver.rs b/servers/src/mining/stratumserver.rs index e22e4df9..10631dd5 100644 --- a/servers/src/mining/stratumserver.rs +++ b/servers/src/mining/stratumserver.rs @@ -475,7 +475,7 @@ impl StratumServer { b.header.pow.nonce = params.nonce; b.header.pow.proof.nonces = params.pow; // Get share difficulty - share_difficulty = b.header.pow.to_difficulty().to_num(); + share_difficulty = b.header.pow.to_difficulty(b.header.height).to_num(); // If the difficulty is too low its an error if share_difficulty < self.minimum_share_difficulty { // Return error status diff --git a/servers/src/mining/test_miner.rs b/servers/src/mining/test_miner.rs index 381b768b..f5eee483 100644 --- a/servers/src/mining/test_miner.rs +++ b/servers/src/mining/test_miner.rs @@ -104,7 +104,7 @@ impl Miner { .unwrap(); if let Ok(proofs) = ctx.find_cycles() { b.header.pow.proof = proofs[0].clone(); - let proof_diff = b.header.pow.to_difficulty(); + let proof_diff = b.header.pow.to_difficulty(b.header.height); if proof_diff >= (b.header.total_difficulty() - head.total_difficulty()) { return true; } diff --git a/src/bin/tui/mining.rs b/src/bin/tui/mining.rs index 241f4457..4156a573 100644 --- a/src/bin/tui/mining.rs +++ b/src/bin/tui/mining.rs @@ -307,7 +307,7 @@ impl TUIStatusListener for TUIMiningView { let stratum_network_hashrate = format!( "Network Hashrate: {:.*}", 2, - stratum_stats.network_hashrate() + stratum_stats.network_hashrate(stratum_stats.block_height) ); let worker_stats = stratum_stats.worker_stats; let stratum_enabled = format!("Mining server enabled: {}", stratum_stats.is_enabled);