From 3ced77b8d12706ba10ed996cb66d5668d037d735 Mon Sep 17 00:00:00 2001 From: John Tromp Date: Wed, 20 Nov 2019 21:55:20 +0100 Subject: [PATCH 1/4] add 2nd HF and cuckaroom --- core/src/consensus.rs | 17 ++-- core/src/global.rs | 9 +- core/src/pow.rs | 2 + core/src/pow/cuckaroom.rs | 189 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 210 insertions(+), 7 deletions(-) create mode 100644 core/src/pow/cuckaroom.rs diff --git a/core/src/consensus.rs b/core/src/consensus.rs index c3920d23de..dc2bda3baa 100644 --- a/core/src/consensus.rs +++ b/core/src/consensus.rs @@ -130,6 +130,9 @@ pub const HARD_FORK_INTERVAL: u64 = YEAR_HEIGHT / 2; /// Floonet first hard fork height, set to happen around 2019-06-20 pub const FLOONET_FIRST_HARD_FORK: u64 = 185_040; +/// Floonet second hard fork height, set to happen around 2019-12-19 +pub const FLOONET_SECOND_HARD_FORK: u64 = 303_696; + /// Check whether the block version is valid at a given height, implements /// 6 months interval scheduled hard forks for the first 2 years. pub fn valid_header_version(height: u64, version: HeaderVersion) -> bool { @@ -138,10 +141,12 @@ pub fn valid_header_version(height: u64, version: HeaderVersion) -> bool { global::ChainTypes::Floonet => { if height < FLOONET_FIRST_HARD_FORK { version == HeaderVersion::default() - // add branches one by one as we go from hard fork to hard fork - // } else if height < FLOONET_SECOND_HARD_FORK { - } else if height < 2 * HARD_FORK_INTERVAL { + } else if height < FLOONET_SECOND_HARD_FORK { version == HeaderVersion::new(2) + // add branches one by one as we go from hard fork to hard fork + // } else if height < FLOONET_THIRD_HARD_FORK { + } else if height < 3 * HARD_FORK_INTERVAL { + version == HeaderVersion::new(3) } else { false } @@ -152,10 +157,10 @@ pub fn valid_header_version(height: u64, version: HeaderVersion) -> bool { version == HeaderVersion::default() } else if height < 2 * HARD_FORK_INTERVAL { version == HeaderVersion::new(2) - // uncomment branches one by one as we go from hard fork to hard fork - /*} else if height < 3 * HARD_FORK_INTERVAL { + } else if height < 3 * HARD_FORK_INTERVAL { version == HeaderVersion::new(3) - } else if height < 4 * HARD_FORK_INTERVAL { + // uncomment branches one by one as we go from hard fork to hard fork + /*} } else if height < 4 * HARD_FORK_INTERVAL { version == HeaderVersion::new(4) } else { version > HeaderVersion::new(4) */ diff --git a/core/src/global.rs b/core/src/global.rs index 229c9889cc..f45798d6b8 100644 --- a/core/src/global.rs +++ b/core/src/global.rs @@ -24,7 +24,8 @@ use crate::consensus::{ }; use crate::core::block::HeaderVersion; use crate::pow::{ - self, new_cuckaroo_ctx, new_cuckarood_ctx, new_cuckatoo_ctx, EdgeType, PoWContext, + self, new_cuckaroo_ctx, new_cuckarood_ctx, new_cuckaroom_ctx, new_cuckatoo_ctx, EdgeType, + PoWContext, }; use util::RwLock; @@ -175,6 +176,9 @@ where match chain_type { // Mainnet has Cuckaroo(d)29 for AR and Cuckatoo31+ for AF ChainTypes::Mainnet if edge_bits > 29 => new_cuckatoo_ctx(edge_bits, proof_size, max_sols), + ChainTypes::Mainnet if valid_header_version(height, HeaderVersion::new(3)) => { + new_cuckaroom_ctx(edge_bits, proof_size) + } ChainTypes::Mainnet if valid_header_version(height, HeaderVersion::new(2)) => { new_cuckarood_ctx(edge_bits, proof_size) } @@ -182,6 +186,9 @@ where // Same for Floonet ChainTypes::Floonet if edge_bits > 29 => new_cuckatoo_ctx(edge_bits, proof_size, max_sols), + ChainTypes::Floonet if valid_header_version(height, HeaderVersion::new(3)) => { + new_cuckaroom_ctx(edge_bits, proof_size) + } ChainTypes::Floonet if valid_header_version(height, HeaderVersion::new(2)) => { new_cuckarood_ctx(edge_bits, proof_size) } diff --git a/core/src/pow.rs b/core/src/pow.rs index 9cf2d1d001..228f0cac76 100644 --- a/core/src/pow.rs +++ b/core/src/pow.rs @@ -40,6 +40,7 @@ use num; mod common; pub mod cuckaroo; pub mod cuckarood; +pub mod cuckaroom; pub mod cuckatoo; mod error; #[allow(dead_code)] @@ -49,6 +50,7 @@ mod types; pub use crate::pow::cuckaroo::{new_cuckaroo_ctx, CuckarooContext}; pub use crate::pow::cuckarood::{new_cuckarood_ctx, CuckaroodContext}; +pub use crate::pow::cuckaroom::{new_cuckaroom_ctx, CuckaroomContext}; pub use crate::pow::cuckatoo::{new_cuckatoo_ctx, CuckatooContext}; pub use crate::pow::error::Error; use chrono::prelude::{DateTime, NaiveDateTime, Utc}; diff --git a/core/src/pow/cuckaroom.rs b/core/src/pow/cuckaroom.rs new file mode 100644 index 0000000000..84047ba574 --- /dev/null +++ b/core/src/pow/cuckaroom.rs @@ -0,0 +1,189 @@ +// Copyright 2019 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. + +//! Implementation of Cuckaroom Cycle, based on Cuckoo Cycle designed by +//! John Tromp. Ported to Rust from https://github.com/tromp/cuckoo. +//! +//! Cuckaroom is a variation of Cuckaroo that's tweaked at the second HardFork +//! to maintain ASIC-Resistance, as introduced in +//! https://www.grin-forum.org/t/mid-december-pow-hardfork-cuckarood29-cuckaroom29 +//! It uses a tweaked edge block generation where states are xored with all later +//! states, reverts to standard siphash, and most importantly, identifies cycles +//! in a mono-partite graph, from which it derives the letter 'm'. + +use crate::global; +use crate::pow::common::{CuckooParams, EdgeType}; +use crate::pow::error::{Error, ErrorKind}; +use crate::pow::siphash::siphash_block; +use crate::pow::{PoWContext, Proof}; + +/// Instantiate a new CuckaroomContext as a PowContext. Note that this can't +/// be moved in the PoWContext trait as this particular trait needs to be +/// convertible to an object trait. +pub fn new_cuckaroom_ctx( + edge_bits: u8, + proof_size: usize, +) -> Result>, Error> +where + T: EdgeType + 'static, +{ + let params = CuckooParams::new(edge_bits, proof_size)?; + Ok(Box::new(CuckaroomContext { params })) +} + +/// Cuckaroom cycle context. Only includes the verifier for now. +pub struct CuckaroomContext +where + T: EdgeType, +{ + params: CuckooParams, +} + +impl PoWContext for CuckaroomContext +where + T: EdgeType, +{ + fn set_header_nonce( + &mut self, + header: Vec, + nonce: Option, + _solve: bool, + ) -> Result<(), Error> { + self.params.reset_header_nonce(header, nonce) + } + + fn find_cycles(&mut self) -> Result, Error> { + unimplemented!() + } + + fn verify(&self, proof: &Proof) -> Result<(), Error> { + let proofsize = proof.proof_size(); + if proofsize != global::proofsize() { + return Err(ErrorKind::Verification("wrong cycle length".to_owned()))?; + } + let nonces = &proof.nonces; + let mut from = vec![0u32; proofsize]; + let mut to = vec![0u32; proofsize]; + let mut xor_from: u32 = 0; + let mut xor_to: u32 = 0; + let nodemask = self.params.edge_mask >> 1; + + for n in 0..proofsize { + if nonces[n] > to_u64!(self.params.edge_mask) { + return Err(ErrorKind::Verification("edge too big".to_owned()))?; + } + if n > 0 && nonces[n] <= nonces[n - 1] { + return Err(ErrorKind::Verification("edges not ascending".to_owned()))?; + } + let edge = to_edge!(T, siphash_block(&self.params.siphash_keys, nonces[n], 21)); + from[n] = to_u32!(edge & nodemask); + xor_from ^= from[n]; + to[n] = to_u32!((edge >> 32) & nodemask); + xor_to ^= to[n]; + } + if xor_from != xor_to { + return Err(ErrorKind::Verification( + "endpoints don't match up".to_owned(), + ))?; + } + let mut visited = vec![false; proofsize]; + let mut n = 0; + let mut i = 0; + loop { + // follow cycle + if visited[i] { + return Err(ErrorKind::Verification("branch in cycle".to_owned()))?; + } + visited[i] = true; + let mut nexti = 0; + while from[nexti] != to[i] { + nexti += 1; + if nexti == proofsize { + return Err(ErrorKind::Verification("cycle dead ends".to_owned()))?; + } + } + i = nexti; + n += 1; + if i == 0 { + // must cycle back to start or find branch + break; + } + } + if n == proofsize { + Ok(()) + } else { + Err(ErrorKind::Verification("cycle too short".to_owned()))? + } + } +} + +#[cfg(test)] +mod test { + use super::*; + + // empty header, nonce 64 + static V1_19_HASH: [u64; 4] = [ + 0xdb7896f799c76dab, + 0x352e8bf25df7a723, + 0xf0aa29cbb1150ea6, + 0x3206c2759f41cbd5, + ]; + static V1_19_SOL: [u64; 42] = [ + 0x0413c, 0x05121, 0x0546e, 0x1293a, 0x1dd27, 0x1e13e, 0x1e1d2, 0x22870, 0x24642, 0x24833, + 0x29190, 0x2a732, 0x2ccf6, 0x302cf, 0x32d9a, 0x33700, 0x33a20, 0x351d9, 0x3554b, 0x35a70, + 0x376c1, 0x398c6, 0x3f404, 0x3ff0c, 0x48b26, 0x49a03, 0x4c555, 0x4dcda, 0x4dfcd, 0x4fbb6, + 0x50275, 0x584a8, 0x5da0d, 0x5dbf1, 0x6038f, 0x66540, 0x72bbd, 0x77323, 0x77424, 0x77a14, + 0x77dc9, 0x7d9dc, + ]; + + // empty header, nonce 15 + static V2_29_HASH: [u64; 4] = [ + 0xe4b4a751f2eac47d, + 0x3115d47edfb69267, + 0x87de84146d9d609e, + 0x7deb20eab6d976a1, + ]; + static V2_29_SOL: [u64; 42] = [ + 0x04acd28, 0x29ccf71, 0x2a5572b, 0x2f31c2c, 0x2f60c37, 0x317fe1d, 0x32f6d4c, 0x3f51227, + 0x45ee1dc, 0x535eeb8, 0x5e135d5, 0x6184e3d, 0x6b1b8e0, 0x6f857a9, 0x8916a0f, 0x9beb5f8, + 0xa3c8dc9, 0xa886d94, 0xaab6a57, 0xd6df8f8, 0xe4d630f, 0xe6ae422, 0xea2d658, 0xf7f369b, + 0x10c465d8, 0x1130471e, 0x12049efb, 0x12f43bc5, 0x15b493a6, 0x16899354, 0x1915dfca, + 0x195c3dac, 0x19b09ab6, 0x1a1a8ed7, 0x1bba748f, 0x1bdbf777, 0x1c806542, 0x1d201b53, + 0x1d9e6af7, 0x1e99885e, 0x1f255834, 0x1f9c383b, + ]; + + #[test] + fn cuckaroom19_29_vectors() { + let mut ctx19 = new_impl::(19, 42); + ctx19.params.siphash_keys = V1_19_HASH.clone(); + assert!(ctx19 + .verify(&Proof::new(V1_19_SOL.to_vec().clone())) + .is_ok()); + assert!(ctx19.verify(&Proof::zero(42)).is_err()); + let mut ctx29 = new_impl::(29, 42); + ctx29.params.siphash_keys = V2_29_HASH.clone(); + assert!(ctx29 + .verify(&Proof::new(V2_29_SOL.to_vec().clone())) + .is_ok()); + assert!(ctx29.verify(&Proof::zero(42)).is_err()); + } + + fn new_impl(edge_bits: u8, proof_size: usize) -> CuckaroomContext + where + T: EdgeType, + { + let params = CuckooParams::new(edge_bits, proof_size).unwrap(); + CuckaroomContext { params } + } +} From 2bc07008d7e56d5600d57c2cdc64521372f76564 Mon Sep 17 00:00:00 2001 From: John Tromp Date: Mon, 25 Nov 2019 18:49:23 +0100 Subject: [PATCH 2/4] add cuckaroom and hardfork tests --- core/src/consensus.rs | 2 +- core/src/pow/cuckaroo.rs | 5 ++- core/src/pow/cuckarood.rs | 5 ++- core/src/pow/cuckaroom.rs | 5 ++- core/src/pow/siphash.rs | 42 +++++++++++++------- core/tests/consensus.rs | 83 ++++++++++++++++++++++++++++++++++----- 6 files changed, 113 insertions(+), 29 deletions(-) diff --git a/core/src/consensus.rs b/core/src/consensus.rs index dc2bda3baa..602e56989d 100644 --- a/core/src/consensus.rs +++ b/core/src/consensus.rs @@ -131,7 +131,7 @@ pub const HARD_FORK_INTERVAL: u64 = YEAR_HEIGHT / 2; pub const FLOONET_FIRST_HARD_FORK: u64 = 185_040; /// Floonet second hard fork height, set to happen around 2019-12-19 -pub const FLOONET_SECOND_HARD_FORK: u64 = 303_696; +pub const FLOONET_SECOND_HARD_FORK: u64 = 298_080; /// Check whether the block version is valid at a given height, implements /// 6 months interval scheduled hard forks for the first 2 years. diff --git a/core/src/pow/cuckaroo.rs b/core/src/pow/cuckaroo.rs index 7e46331532..0e14525b4b 100644 --- a/core/src/pow/cuckaroo.rs +++ b/core/src/pow/cuckaroo.rs @@ -85,7 +85,10 @@ where return Err(ErrorKind::Verification("edges not ascending".to_owned()))?; } // 21 is standard siphash rotation constant - let edge = to_edge!(T, siphash_block(&self.params.siphash_keys, nonces[n], 21)); + let edge = to_edge!( + T, + siphash_block(&self.params.siphash_keys, nonces[n], 21, false) + ); uvs[2 * n] = to_u64!(edge & self.params.edge_mask); uvs[2 * n + 1] = to_u64!((edge >> 32) & self.params.edge_mask); xor0 ^= uvs[2 * n]; diff --git a/core/src/pow/cuckarood.rs b/core/src/pow/cuckarood.rs index f6a786252a..3748e9a72c 100644 --- a/core/src/pow/cuckarood.rs +++ b/core/src/pow/cuckarood.rs @@ -89,7 +89,10 @@ where if n > 0 && nonces[n] <= nonces[n - 1] { return Err(ErrorKind::Verification("edges not ascending".to_owned()))?; } - let edge = to_edge!(T, siphash_block(&self.params.siphash_keys, nonces[n], 25)); + let edge = to_edge!( + T, + siphash_block(&self.params.siphash_keys, nonces[n], 25, false) + ); let idx = 4 * ndir[dir] + 2 * dir; uvs[idx] = to_u64!(edge & nodemask); uvs[idx + 1] = to_u64!((edge >> 32) & nodemask); diff --git a/core/src/pow/cuckaroom.rs b/core/src/pow/cuckaroom.rs index 84047ba574..a3aa051bf5 100644 --- a/core/src/pow/cuckaroom.rs +++ b/core/src/pow/cuckaroom.rs @@ -86,7 +86,10 @@ where if n > 0 && nonces[n] <= nonces[n - 1] { return Err(ErrorKind::Verification("edges not ascending".to_owned()))?; } - let edge = to_edge!(T, siphash_block(&self.params.siphash_keys, nonces[n], 21)); + let edge = to_edge!( + T, + siphash_block(&self.params.siphash_keys, nonces[n], 21, true) + ); from[n] = to_u32!(edge & nodemask); xor_from ^= from[n]; to[n] = to_u32!((edge >> 32) & nodemask); diff --git a/core/src/pow/siphash.rs b/core/src/pow/siphash.rs index 12c26d17e4..d3edfb7abc 100644 --- a/core/src/pow/siphash.rs +++ b/core/src/pow/siphash.rs @@ -39,26 +39,29 @@ pub fn siphash24(v: &[u64; 4], nonce: u64) -> u64 { /// Builds a block of siphash values by repeatedly hashing from the nonce /// truncated to its closest block start, up to the end of the block. Returns /// the resulting hash at the nonce's position. -pub fn siphash_block(v: &[u64; 4], nonce: u64, rot_e: u8) -> u64 { +pub fn siphash_block(v: &[u64; 4], nonce: u64, rot_e: u8, xor_all: bool) -> u64 { // beginning of the block of hashes let nonce0 = nonce & !SIPHASH_BLOCK_MASK; - let mut nonce_hash = 0; + let nonce_i = nonce & SIPHASH_BLOCK_MASK; + let mut nonce_hash = vec![0u64; SIPHASH_BLOCK_SIZE as usize]; // repeated hashing over the whole block let mut siphash = SipHash24::new(v); - for n in nonce0..(nonce0 + SIPHASH_BLOCK_SIZE) { - siphash.hash(n, rot_e); - if n == nonce { - nonce_hash = siphash.digest(); - } + for i in 0..SIPHASH_BLOCK_SIZE { + siphash.hash(nonce0 + i, rot_e); + nonce_hash[i as usize] = siphash.digest(); } - // xor the nonce with the last hash to force hashing the whole block - // unless the nonce is last in the block - if nonce == nonce0 + SIPHASH_BLOCK_MASK { - return siphash.digest(); + // xor the hash at nonce_i < SIPHASH_BLOCK_MASK with some or all later hashes to force hashing the whole block + let mut xor: u64 = nonce_hash[nonce_i as usize]; + let xor_from = if xor_all || nonce_i == SIPHASH_BLOCK_MASK { + nonce_i + 1 } else { - return nonce_hash ^ siphash.digest(); + SIPHASH_BLOCK_MASK + }; + for i in xor_from..SIPHASH_BLOCK_SIZE { + xor ^= nonce_hash[i as usize]; } + return xor; } /// Implements siphash 2-4 specialized for a 4 u64 array key and a u64 nonce @@ -130,8 +133,17 @@ mod test { #[test] fn hash_block() { - assert_eq!(siphash_block(&[1, 2, 3, 4], 10, 21), 1182162244994096396); - assert_eq!(siphash_block(&[1, 2, 3, 4], 123, 21), 11303676240481718781); - assert_eq!(siphash_block(&[9, 7, 6, 7], 12, 21), 4886136884237259030); + assert_eq!( + siphash_block(&[1, 2, 3, 4], 10, 21, false), + 1182162244994096396 + ); + assert_eq!( + siphash_block(&[1, 2, 3, 4], 123, 21, false), + 11303676240481718781 + ); + assert_eq!( + siphash_block(&[9, 7, 6, 7], 12, 21, false), + 4886136884237259030 + ); } } diff --git a/core/tests/consensus.rs b/core/tests/consensus.rs index c3f2e4909c..2f71ab2305 100644 --- a/core/tests/consensus.rs +++ b/core/tests/consensus.rs @@ -640,18 +640,40 @@ fn hard_forks() { HeaderVersion::new(1) )); assert!(!valid_header_version(YEAR_HEIGHT, HeaderVersion::new(1))); - // v3 not active yet - assert!(!valid_header_version(YEAR_HEIGHT, HeaderVersion::new(3))); + + assert!(valid_header_version(YEAR_HEIGHT - 1, HeaderVersion::new(2))); + assert!(valid_header_version(YEAR_HEIGHT, HeaderVersion::new(3))); + assert!(valid_header_version(YEAR_HEIGHT + 1, HeaderVersion::new(3))); assert!(!valid_header_version(YEAR_HEIGHT, HeaderVersion::new(2))); - assert!(!valid_header_version(YEAR_HEIGHT, HeaderVersion::new(1))); assert!(!valid_header_version( YEAR_HEIGHT * 3 / 2, HeaderVersion::new(2) )); + // v4 not active yet assert!(!valid_header_version( - YEAR_HEIGHT + 1, + YEAR_HEIGHT * 3 / 2, + HeaderVersion::new(4) + )); + assert!(!valid_header_version( + YEAR_HEIGHT * 3 / 2, + HeaderVersion::new(3) + )); + assert!(!valid_header_version( + YEAR_HEIGHT * 3 / 2, HeaderVersion::new(2) )); + assert!(!valid_header_version( + YEAR_HEIGHT * 3 / 2, + HeaderVersion::new(1) + )); + assert!(!valid_header_version( + YEAR_HEIGHT * 2, + HeaderVersion::new(3) + )); + assert!(!valid_header_version( + YEAR_HEIGHT * 3 / 2 + 1, + HeaderVersion::new(3) + )); } // Tests for floonet chain type. { @@ -677,17 +699,58 @@ fn hard_forks() { HeaderVersion::new(1) )); assert!(!valid_header_version(YEAR_HEIGHT, HeaderVersion::new(1))); - // v3 not active yet - assert!(!valid_header_version(YEAR_HEIGHT, HeaderVersion::new(3))); - assert!(!valid_header_version(YEAR_HEIGHT, HeaderVersion::new(2))); - assert!(!valid_header_version(YEAR_HEIGHT, HeaderVersion::new(1))); + assert!(valid_header_version( + FLOONET_SECOND_HARD_FORK - 1, + HeaderVersion::new(2) + )); + assert!(valid_header_version( + FLOONET_SECOND_HARD_FORK, + HeaderVersion::new(3) + )); + assert!(valid_header_version( + FLOONET_SECOND_HARD_FORK + 1, + HeaderVersion::new(3) + )); assert!(!valid_header_version( - YEAR_HEIGHT * 3 / 2, + FLOONET_SECOND_HARD_FORK, + HeaderVersion::new(2) + )); + assert!(!valid_header_version( + FLOONET_SECOND_HARD_FORK, + HeaderVersion::new(1) + )); + + assert!(!valid_header_version( + YEAR_HEIGHT - 1, HeaderVersion::new(2) )); + assert!(valid_header_version(YEAR_HEIGHT - 1, HeaderVersion::new(3))); + assert!(valid_header_version(YEAR_HEIGHT, HeaderVersion::new(3))); + assert!(valid_header_version(YEAR_HEIGHT + 1, HeaderVersion::new(3))); + // v4 not active yet + assert!(!valid_header_version( + YEAR_HEIGHT * 3 / 2, + HeaderVersion::new(4) + )); assert!(!valid_header_version( - YEAR_HEIGHT + 1, + YEAR_HEIGHT * 3 / 2, + HeaderVersion::new(3) + )); + assert!(!valid_header_version( + YEAR_HEIGHT * 3 / 2, HeaderVersion::new(2) )); + assert!(!valid_header_version( + YEAR_HEIGHT * 3 / 2, + HeaderVersion::new(1) + )); + assert!(!valid_header_version( + YEAR_HEIGHT * 2, + HeaderVersion::new(3) + )); + assert!(!valid_header_version( + YEAR_HEIGHT * 3 / 2 + 1, + HeaderVersion::new(3) + )); } } From 9447bc9e6b66148fb4e687423f5e0eb7c7e890f7 Mon Sep 17 00:00:00 2001 From: John Tromp Date: Mon, 25 Nov 2019 22:32:38 +0100 Subject: [PATCH 3/4] remove all traces of later phaseouts --- core/src/consensus.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/core/src/consensus.rs b/core/src/consensus.rs index 602e56989d..7fb4952199 100644 --- a/core/src/consensus.rs +++ b/core/src/consensus.rs @@ -78,7 +78,7 @@ pub const PROOFSIZE: usize = 42; /// Default Cuckatoo Cycle edge_bits, used for mining and validating. pub const DEFAULT_MIN_EDGE_BITS: u8 = 31; -/// Cuckaroo proof-of-work edge_bits, meant to be ASIC resistant. +/// Cuckaroo* proof-of-work edge_bits, meant to be ASIC resistant. pub const SECOND_POW_EDGE_BITS: u8 = 29; /// Original reference edge_bits to compute difficulty factors for higher @@ -193,13 +193,14 @@ pub const AR_SCALE_DAMP_FACTOR: u64 = 13; 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.saturating_sub(global::min_edge_bits()); - let expiry_height = (1 << bits_over_min) * YEAR_HEIGHT; - if edge_bits < 32 && height >= expiry_height { + let expiry_height = YEAR_HEIGHT; + if edge_bits == 31 && height >= expiry_height { xpr_edge_bits = xpr_edge_bits.saturating_sub(1 + (height - expiry_height) / WEEK_HEIGHT); } + // For C31 xpr_edge_bits reaches 0 at height YEAR_HEIGHT + 30 * WEEK_HEIGHT + // 30 weeks after Jan 15, 2020 would be Aug 12, 2020 - (2 << (edge_bits - global::base_edge_bits()) as u64) * xpr_edge_bits + (2u64 << (edge_bits - global::base_edge_bits()) as u64) * xpr_edge_bits } /// Minimum difficulty, enforced in diff retargetting From 83bf959ad34a391d6a3c6c5ce628b72b5d1241a0 Mon Sep 17 00:00:00 2001 From: John Tromp Date: Wed, 27 Nov 2019 14:36:18 +0100 Subject: [PATCH 4/4] refactor header_version from valid_header_version --- core/src/consensus.rs | 38 ++++++++++++++------------------------ 1 file changed, 14 insertions(+), 24 deletions(-) diff --git a/core/src/consensus.rs b/core/src/consensus.rs index 7fb4952199..0c7a2eb135 100644 --- a/core/src/consensus.rs +++ b/core/src/consensus.rs @@ -133,44 +133,34 @@ pub const FLOONET_FIRST_HARD_FORK: u64 = 185_040; /// Floonet second hard fork height, set to happen around 2019-12-19 pub const FLOONET_SECOND_HARD_FORK: u64 = 298_080; -/// Check whether the block version is valid at a given height, implements +/// Compute possible block version at a given height, implements /// 6 months interval scheduled hard forks for the first 2 years. -pub fn valid_header_version(height: u64, version: HeaderVersion) -> bool { +pub fn header_version(height: u64) -> HeaderVersion { let chain_type = global::CHAIN_TYPE.read().clone(); + let hf_interval = (1 + height / HARD_FORK_INTERVAL) as u16; match chain_type { global::ChainTypes::Floonet => { if height < FLOONET_FIRST_HARD_FORK { - version == HeaderVersion::default() + (HeaderVersion::new(1)) } else if height < FLOONET_SECOND_HARD_FORK { - version == HeaderVersion::new(2) - // add branches one by one as we go from hard fork to hard fork - // } else if height < FLOONET_THIRD_HARD_FORK { + (HeaderVersion::new(2)) } else if height < 3 * HARD_FORK_INTERVAL { - version == HeaderVersion::new(3) + (HeaderVersion::new(3)) } else { - false + HeaderVersion::new(hf_interval) } } // everything else just like mainnet - _ => { - if height < HARD_FORK_INTERVAL { - version == HeaderVersion::default() - } else if height < 2 * HARD_FORK_INTERVAL { - version == HeaderVersion::new(2) - } else if height < 3 * HARD_FORK_INTERVAL { - version == HeaderVersion::new(3) - // uncomment branches one by one as we go from hard fork to hard fork - /*} } else if height < 4 * HARD_FORK_INTERVAL { - version == HeaderVersion::new(4) - } else { - version > HeaderVersion::new(4) */ - } else { - false - } - } + _ => HeaderVersion::new(hf_interval), } } +/// Check whether the block version is valid at a given height, implements +/// 6 months interval scheduled hard forks for the first 2 years. +pub fn valid_header_version(height: u64, version: HeaderVersion) -> bool { + return height < 3 * HARD_FORK_INTERVAL && version == header_version(height); +} + /// Number of blocks used to calculate difficulty adjustments pub const DIFFICULTY_ADJUST_WINDOW: u64 = HOUR_HEIGHT;