mirror of
https://github.com/mimblewimble/grin.git
synced 2025-01-20 19:11:08 +03:00
Hardfork2 (#3136)
* add 2nd HF and cuckaroom * add cuckaroom and hardfork tests * remove all traces of later phaseouts * refactor header_version from valid_header_version
This commit is contained in:
parent
e2795b1593
commit
82b1ff905d
8 changed files with 336 additions and 58 deletions
|
@ -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
|
||||
|
@ -130,42 +130,37 @@ 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;
|
||||
|
||||
/// Check whether the block version is valid at a given height, implements
|
||||
/// Floonet second hard fork height, set to happen around 2019-12-19
|
||||
pub const FLOONET_SECOND_HARD_FORK: u64 = 298_080;
|
||||
|
||||
/// 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()
|
||||
// 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 {
|
||||
version == HeaderVersion::new(2)
|
||||
(HeaderVersion::new(1))
|
||||
} else if height < FLOONET_SECOND_HARD_FORK {
|
||||
(HeaderVersion::new(2))
|
||||
} else if height < 3 * HARD_FORK_INTERVAL {
|
||||
(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)
|
||||
// uncomment branches one by one as we go from hard fork to hard fork
|
||||
/*} else if height < 3 * HARD_FORK_INTERVAL {
|
||||
version == HeaderVersion::new(3)
|
||||
} 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;
|
||||
|
||||
|
@ -188,13 +183,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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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);
|
||||
|
|
192
core/src/pow/cuckaroom.rs
Normal file
192
core/src/pow/cuckaroom.rs
Normal file
|
@ -0,0 +1,192 @@
|
|||
// 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<T>(
|
||||
edge_bits: u8,
|
||||
proof_size: usize,
|
||||
) -> Result<Box<dyn PoWContext<T>>, 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<T>
|
||||
where
|
||||
T: EdgeType,
|
||||
{
|
||||
params: CuckooParams<T>,
|
||||
}
|
||||
|
||||
impl<T> PoWContext<T> for CuckaroomContext<T>
|
||||
where
|
||||
T: EdgeType,
|
||||
{
|
||||
fn set_header_nonce(
|
||||
&mut self,
|
||||
header: Vec<u8>,
|
||||
nonce: Option<u32>,
|
||||
_solve: bool,
|
||||
) -> Result<(), Error> {
|
||||
self.params.reset_header_nonce(header, nonce)
|
||||
}
|
||||
|
||||
fn find_cycles(&mut self) -> Result<Vec<Proof>, 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, true)
|
||||
);
|
||||
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::<u64>(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::<u64>(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<T>(edge_bits: u8, proof_size: usize) -> CuckaroomContext<T>
|
||||
where
|
||||
T: EdgeType,
|
||||
{
|
||||
let params = CuckooParams::new(edge_bits, proof_size).unwrap();
|
||||
CuckaroomContext { params }
|
||||
}
|
||||
}
|
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -640,17 +640,39 @@ 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 * 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 + 1,
|
||||
HeaderVersion::new(2)
|
||||
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(
|
||||
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 * 3 / 2,
|
||||
HeaderVersion::new(3)
|
||||
));
|
||||
assert!(!valid_header_version(
|
||||
YEAR_HEIGHT * 3 / 2,
|
||||
HeaderVersion::new(2)
|
||||
));
|
||||
assert!(!valid_header_version(
|
||||
YEAR_HEIGHT + 1,
|
||||
HeaderVersion::new(2)
|
||||
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)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue