Skip to content

Commit

Permalink
HardFork4 (#3478)
Browse files Browse the repository at this point in the history
* HardFork4 initial commit

* HF4 obsoletes secondary_scale, which becomes an nonce extension 8->12 bytes

* fix TESTNET_FOURTH_HARD_FORK height

* improve predicted height for testnet fork on dec 8

* move local variable as suggested by antiochp
  • Loading branch information
tromp committed Nov 24, 2020
1 parent 2125c05 commit a5b8968
Show file tree
Hide file tree
Showing 12 changed files with 128 additions and 244 deletions.
8 changes: 6 additions & 2 deletions chain/src/pipe.rs
Expand Up @@ -18,7 +18,9 @@ use crate::core::consensus;
use crate::core::core::hash::Hashed;
use crate::core::core::verifier_cache::VerifierCache;
use crate::core::core::Committed;
use crate::core::core::{block, Block, BlockHeader, BlockSums, OutputIdentifier, TransactionBody};
use crate::core::core::{
block, Block, BlockHeader, BlockSums, HeaderVersion, OutputIdentifier, TransactionBody,
};
use crate::core::global;
use crate::core::pow;
use crate::error::{Error, ErrorKind};
Expand Down Expand Up @@ -394,7 +396,9 @@ fn validate_header(header: &BlockHeader, ctx: &mut BlockContext<'_>) -> Result<(
return Err(ErrorKind::WrongTotalDifficulty.into());
}
// check the secondary PoW scaling factor if applicable
if header.pow.secondary_scaling != next_header_info.secondary_scaling {
if header.version < HeaderVersion(5)
&& header.pow.secondary_scaling != next_header_info.secondary_scaling
{
info!(
"validate_header: header secondary scaling {} != {}",
header.pow.secondary_scaling, next_header_info.secondary_scaling
Expand Down
37 changes: 12 additions & 25 deletions core/src/consensus.rs
Expand Up @@ -136,43 +136,30 @@ pub const TESTNET_SECOND_HARD_FORK: u64 = 298_080;
/// Testnet second hard fork height, set to happen around 2020-06-20
pub const TESTNET_THIRD_HARD_FORK: u64 = 552_960;

/// AutomatedTesting and UserTesting HF1 height.
pub const TESTING_FIRST_HARD_FORK: u64 = 3;
/// Testnet second hard fork height, set to happen around 2020-12-8
pub const TESTNET_FOURTH_HARD_FORK: u64 = 642_240;

/// AutomatedTesting and UserTesting HF2 height.
pub const TESTING_SECOND_HARD_FORK: u64 = 6;

/// AutomatedTesting and UserTesting HF3 height.
pub const TESTING_THIRD_HARD_FORK: u64 = 9;
/// Fork every 3 blocks
pub const TESTING_HARD_FORK_INTERVAL: u64 = 3;

/// Compute possible block version at a given height, implements
/// 6 months interval scheduled hard forks for the first 2 years.
pub fn header_version(height: u64) -> HeaderVersion {
let chain_type = global::get_chain_type();
let hf_interval = (1 + height / HARD_FORK_INTERVAL) as u16;
match chain_type {
global::ChainTypes::Mainnet => HeaderVersion(hf_interval),
match global::get_chain_type() {
global::ChainTypes::Mainnet => HeaderVersion(min(5, hf_interval)),
global::ChainTypes::AutomatedTesting | global::ChainTypes::UserTesting => {
let testing_hf_interval = (1 + height / TESTING_HARD_FORK_INTERVAL) as u16;
HeaderVersion(min(5, testing_hf_interval))
}
global::ChainTypes::Testnet => {
if height < TESTNET_FIRST_HARD_FORK {
HeaderVersion(1)
} else if height < TESTNET_SECOND_HARD_FORK {
HeaderVersion(2)
} else if height < TESTNET_THIRD_HARD_FORK {
HeaderVersion(3)
} else if height < 4 * HARD_FORK_INTERVAL {
HeaderVersion(4)
} else {
HeaderVersion(hf_interval)
}
}
global::ChainTypes::AutomatedTesting | global::ChainTypes::UserTesting => {
if height < TESTING_FIRST_HARD_FORK {
HeaderVersion(1)
} else if height < TESTING_SECOND_HARD_FORK {
HeaderVersion(2)
} else if height < TESTING_THIRD_HARD_FORK {
HeaderVersion(3)
} else if height < 4 * HARD_FORK_INTERVAL {
} else if height < TESTNET_FOURTH_HARD_FORK {
HeaderVersion(4)
} else {
HeaderVersion(5)
Expand All @@ -184,7 +171,7 @@ pub fn header_version(height: u64) -> HeaderVersion {
/// 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 {
height < 4 * HARD_FORK_INTERVAL && version == header_version(height)
version == header_version(height)
}

/// Number of blocks used to calculate difficulty adjustments
Expand Down
55 changes: 20 additions & 35 deletions core/src/global.rs
Expand Up @@ -17,19 +17,17 @@
//! should be used sparingly.

use crate::consensus::{
graph_weight, valid_header_version, HeaderInfo, BASE_EDGE_BITS, BLOCK_KERNEL_WEIGHT,
graph_weight, header_version, HeaderInfo, BASE_EDGE_BITS, BLOCK_KERNEL_WEIGHT,
BLOCK_OUTPUT_WEIGHT, BLOCK_TIME_SEC, COINBASE_MATURITY, CUT_THROUGH_HORIZON, DAY_HEIGHT,
DEFAULT_MIN_EDGE_BITS, DIFFICULTY_ADJUST_WINDOW, INITIAL_DIFFICULTY, MAX_BLOCK_WEIGHT,
PROOFSIZE, SECOND_POW_EDGE_BITS, STATE_SYNC_THRESHOLD,
};
use crate::core::block::HeaderVersion;
use crate::{
pow::{
self, new_cuckaroo_ctx, new_cuckarood_ctx, new_cuckaroom_ctx, new_cuckarooz_ctx,
new_cuckatoo_ctx, BitVec, PoWContext,
},
ser::ProtocolVersion,
use crate::pow::{
self, new_cuckaroo_ctx, new_cuckarood_ctx, new_cuckaroom_ctx, new_cuckarooz_ctx,
new_cuckatoo_ctx, no_cuckaroo_ctx, BitVec, PoWContext,
};
use crate::ser::ProtocolVersion;
use std::cell::Cell;
use util::OneTime;

Expand Down Expand Up @@ -215,7 +213,7 @@ pub fn is_nrd_enabled() -> bool {
})
}

/// Return either a cuckoo context or a cuckatoo context
/// Return either a cuckaroo* context or a cuckatoo context
/// Single change point
pub fn create_pow_context<T>(
height: u64,
Expand All @@ -224,35 +222,22 @@ pub fn create_pow_context<T>(
max_sols: u32,
) -> Result<Box<dyn PoWContext>, pow::Error> {
let chain_type = get_chain_type();
match chain_type {
// Mainnet has Cuckaroo{,d,m,z}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(4)) => {
new_cuckarooz_ctx(edge_bits, proof_size)
}
ChainTypes::Mainnet if valid_header_version(height, HeaderVersion(3)) => {
new_cuckaroom_ctx(edge_bits, proof_size)
}
ChainTypes::Mainnet if valid_header_version(height, HeaderVersion(2)) => {
new_cuckarood_ctx(edge_bits, proof_size)
}
ChainTypes::Mainnet => new_cuckaroo_ctx(edge_bits, proof_size),

// Same for Testnet
ChainTypes::Testnet if edge_bits > 29 => new_cuckatoo_ctx(edge_bits, proof_size, max_sols),
ChainTypes::Testnet if valid_header_version(height, HeaderVersion(4)) => {
new_cuckarooz_ctx(edge_bits, proof_size)
}
ChainTypes::Testnet if valid_header_version(height, HeaderVersion(3)) => {
new_cuckaroom_ctx(edge_bits, proof_size)
}
ChainTypes::Testnet if valid_header_version(height, HeaderVersion(2)) => {
new_cuckarood_ctx(edge_bits, proof_size)
if chain_type == ChainTypes::Mainnet || chain_type == ChainTypes::Testnet {
// Mainnet and Testnet have Cuckatoo31+ for AF and Cuckaroo{,d,m,z}29 for AR
if edge_bits > 29 {
new_cuckatoo_ctx(edge_bits, proof_size, max_sols)
} else {
match header_version(height) {
HeaderVersion(1) => new_cuckaroo_ctx(edge_bits, proof_size),
HeaderVersion(2) => new_cuckarood_ctx(edge_bits, proof_size),
HeaderVersion(3) => new_cuckaroom_ctx(edge_bits, proof_size),
HeaderVersion(4) => new_cuckarooz_ctx(edge_bits, proof_size),
_ => no_cuckaroo_ctx(),
}
}
ChainTypes::Testnet => new_cuckaroo_ctx(edge_bits, proof_size),

} else {
// Everything else is Cuckatoo only
_ => new_cuckatoo_ctx(edge_bits, proof_size, max_sols),
new_cuckatoo_ctx(edge_bits, proof_size, max_sols)
}
}

Expand Down
2 changes: 1 addition & 1 deletion core/src/pow.rs
Expand Up @@ -49,7 +49,7 @@ pub mod lean;
mod siphash;
mod types;

pub use crate::pow::cuckaroo::{new_cuckaroo_ctx, CuckarooContext};
pub use crate::pow::cuckaroo::{new_cuckaroo_ctx, no_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::cuckarooz::{new_cuckarooz_ctx, CuckaroozContext};
Expand Down
5 changes: 5 additions & 0 deletions core/src/pow/cuckaroo.rs
Expand Up @@ -37,6 +37,11 @@ pub fn new_cuckaroo_ctx(edge_bits: u8, proof_size: usize) -> Result<Box<dyn PoWC
Ok(Box::new(CuckarooContext { params }))
}

/// Error returned for cuckaroo request beyond HardFork4
pub fn no_cuckaroo_ctx() -> Result<Box<dyn PoWContext>, Error> {
Err(ErrorKind::Verification("no cuckaroo past HardFork4".to_owned()).into())
}

/// Cuckaroo cycle context. Only includes the verifier for now.
pub struct CuckarooContext {
params: CuckooParams,
Expand Down
2 changes: 2 additions & 0 deletions core/src/pow/types.rs
Expand Up @@ -214,6 +214,8 @@ pub struct ProofOfWork {
/// Total accumulated difficulty since genesis block
pub total_difficulty: Difficulty,
/// Variable difficulty scaling factor fo secondary proof of work
/// After HardFork4, which obsoletes secondary PoW, this effectively
/// becomes 4 more bytes of nonce. might be repurposed in future.
pub secondary_scaling: u32,
/// Nonce increment used to mine this block.
pub nonce: u64,
Expand Down
19 changes: 9 additions & 10 deletions core/tests/block.rs
Expand Up @@ -14,7 +14,7 @@

mod common;
use crate::common::{new_block, tx1i2o, tx2i1o, txspend1i1o};
use crate::core::consensus::{self, BLOCK_OUTPUT_WEIGHT, TESTING_THIRD_HARD_FORK};
use crate::core::consensus::{self, BLOCK_OUTPUT_WEIGHT, TESTING_HARD_FORK_INTERVAL};
use crate::core::core::block::{Block, BlockHeader, Error, HeaderVersion, UntrustedBlockHeader};
use crate::core::core::hash::Hashed;
use crate::core::core::id::ShortIdentifiable;
Expand Down Expand Up @@ -95,7 +95,6 @@ fn block_with_nrd_kernel_pre_post_hf3() {
// Enable the global NRD feature flag. NRD kernels valid at HF3 at height 9.
global::set_local_chain_type(global::ChainTypes::AutomatedTesting);
global::set_local_nrd_enabled(true);

let keychain = ExtKeychain::from_random_seed(false).unwrap();
let builder = ProofBuilder::new(&keychain);
let key_id1 = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
Expand All @@ -113,7 +112,7 @@ fn block_with_nrd_kernel_pre_post_hf3() {
.unwrap();
let txs = &[tx];

let prev_height = TESTING_THIRD_HARD_FORK - 2;
let prev_height = 3 * TESTING_HARD_FORK_INTERVAL - 2;
let prev = BlockHeader {
height: prev_height,
version: consensus::header_version(prev_height),
Expand All @@ -134,7 +133,7 @@ fn block_with_nrd_kernel_pre_post_hf3() {
Err(Error::NRDKernelPreHF3)
);

let prev_height = TESTING_THIRD_HARD_FORK - 1;
let prev_height = 3 * TESTING_HARD_FORK_INTERVAL - 1;
let prev = BlockHeader {
height: prev_height,
version: consensus::header_version(prev_height),
Expand All @@ -149,13 +148,13 @@ fn block_with_nrd_kernel_pre_post_hf3() {
);

// Block is valid at header version 4 (at HF height) if it contains an NRD kernel.
assert_eq!(b.header.height, TESTING_THIRD_HARD_FORK);
assert_eq!(b.header.height, 3 * TESTING_HARD_FORK_INTERVAL);
assert_eq!(b.header.version, HeaderVersion(4));
assert!(b
.validate(&BlindingFactor::zero(), verifier_cache())
.is_ok());

let prev_height = TESTING_THIRD_HARD_FORK;
let prev_height = 3 * TESTING_HARD_FORK_INTERVAL;
let prev = BlockHeader {
height: prev_height,
version: consensus::header_version(prev_height),
Expand Down Expand Up @@ -199,7 +198,7 @@ fn block_with_nrd_kernel_nrd_not_enabled() {

let txs = &[tx];

let prev_height = TESTING_THIRD_HARD_FORK - 2;
let prev_height = 3 * TESTING_HARD_FORK_INTERVAL - 2;
let prev = BlockHeader {
height: prev_height,
version: consensus::header_version(prev_height),
Expand All @@ -220,7 +219,7 @@ fn block_with_nrd_kernel_nrd_not_enabled() {
Err(Error::NRDKernelNotEnabled)
);

let prev_height = TESTING_THIRD_HARD_FORK - 1;
let prev_height = 3 * TESTING_HARD_FORK_INTERVAL - 1;
let prev = BlockHeader {
height: prev_height,
version: consensus::header_version(prev_height),
Expand All @@ -235,14 +234,14 @@ fn block_with_nrd_kernel_nrd_not_enabled() {
);

// Block is invalid as NRD not enabled.
assert_eq!(b.header.height, TESTING_THIRD_HARD_FORK);
assert_eq!(b.header.height, 3 * TESTING_HARD_FORK_INTERVAL);
assert_eq!(b.header.version, HeaderVersion(4));
assert_eq!(
b.validate(&BlindingFactor::zero(), verifier_cache()),
Err(Error::NRDKernelNotEnabled)
);

let prev_height = TESTING_THIRD_HARD_FORK;
let prev_height = 3 * TESTING_HARD_FORK_INTERVAL;
let prev = BlockHeader {
height: prev_height,
version: consensus::header_version(prev_height),
Expand Down
87 changes: 18 additions & 69 deletions core/tests/consensus_mainnet.rs
Expand Up @@ -435,73 +435,22 @@ fn test_secondary_pow_scale() {
fn hard_forks() {
global::set_local_chain_type(global::ChainTypes::Mainnet);

assert!(valid_header_version(0, HeaderVersion(1)));
assert!(valid_header_version(10, HeaderVersion(1)));
assert!(!valid_header_version(10, HeaderVersion(2)));
assert!(valid_header_version(
HARD_FORK_INTERVAL - 1,
HeaderVersion(1)
));
assert!(!valid_header_version(HARD_FORK_INTERVAL, HeaderVersion(1)));
assert!(valid_header_version(HARD_FORK_INTERVAL, HeaderVersion(2)));
assert!(valid_header_version(
HARD_FORK_INTERVAL + 1,
HeaderVersion(2)
));

assert!(valid_header_version(
HARD_FORK_INTERVAL * 2 - 1,
HeaderVersion(2)
));
assert!(!valid_header_version(
HARD_FORK_INTERVAL * 2,
HeaderVersion(2)
));
assert!(valid_header_version(
HARD_FORK_INTERVAL * 2,
HeaderVersion(3)
));
assert!(valid_header_version(
HARD_FORK_INTERVAL * 2 + 1,
HeaderVersion(3)
));

assert!(valid_header_version(
HARD_FORK_INTERVAL * 3 - 1,
HeaderVersion(3)
));
assert!(!valid_header_version(
HARD_FORK_INTERVAL * 3,
HeaderVersion(3)
));
assert!(valid_header_version(
HARD_FORK_INTERVAL * 3,
HeaderVersion(4)
));
assert!(valid_header_version(
HARD_FORK_INTERVAL * 3 + 1,
HeaderVersion(4)
));

// v5 not active yet
assert!(!valid_header_version(
HARD_FORK_INTERVAL * 4,
HeaderVersion(5)
));
assert!(!valid_header_version(
HARD_FORK_INTERVAL * 4,
HeaderVersion(4)
));
assert!(!valid_header_version(
HARD_FORK_INTERVAL * 4,
HeaderVersion(3)
));
assert!(!valid_header_version(
HARD_FORK_INTERVAL * 4,
HeaderVersion(2)
));
assert!(!valid_header_version(
HARD_FORK_INTERVAL * 4,
HeaderVersion(1)
));
assert_eq!(header_version(0), HeaderVersion(1));
assert_eq!(header_version(10), HeaderVersion(1));

assert_eq!(header_version(HARD_FORK_INTERVAL - 1), HeaderVersion(1));
assert_eq!(header_version(HARD_FORK_INTERVAL), HeaderVersion(2));
assert_eq!(header_version(HARD_FORK_INTERVAL + 1), HeaderVersion(2));

assert_eq!(header_version(HARD_FORK_INTERVAL * 2 - 1), HeaderVersion(2));
assert_eq!(header_version(HARD_FORK_INTERVAL * 2), HeaderVersion(3));
assert_eq!(header_version(HARD_FORK_INTERVAL * 2 + 1), HeaderVersion(3));

assert_eq!(header_version(HARD_FORK_INTERVAL * 3 - 1), HeaderVersion(3));
assert_eq!(header_version(HARD_FORK_INTERVAL * 3), HeaderVersion(4));
assert_eq!(header_version(HARD_FORK_INTERVAL * 3 + 1), HeaderVersion(4));

assert_eq!(header_version(HARD_FORK_INTERVAL * 4 - 1), HeaderVersion(4));
assert_eq!(header_version(HARD_FORK_INTERVAL * 4), HeaderVersion(5));
assert_eq!(header_version(HARD_FORK_INTERVAL * 4 + 1), HeaderVersion(5));
}

0 comments on commit a5b8968

Please sign in to comment.