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
This commit is contained in:
Ignotus Peverell
2018-11-28 14:05:55 -08:00
committed by GitHub
parent 7dee490962
commit 28e0d97e64
9 changed files with 69 additions and 16 deletions
+1 -1
View File
@@ -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());
}
+54 -2
View File
@@ -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<T> {
/// 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);
}
}
+2 -2
View File
@@ -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,
}
}
+2 -2
View File
@@ -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());
}
}
+4 -4
View File
@@ -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)
}
}
+3 -2
View File
@@ -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
}
}
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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;
}
+1 -1
View File
@@ -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);