use crate::consensus::{
graph_weight, valid_header_version, HeaderInfo, BASE_EDGE_BITS, 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_cuckatoo_ctx, EdgeType, PoWContext,
};
use crate::util::RwLock;
pub const AUTOMATED_TESTING_MIN_EDGE_BITS: u8 = 9;
pub const AUTOMATED_TESTING_PROOF_SIZE: usize = 4;
pub const USER_TESTING_MIN_EDGE_BITS: u8 = 15;
pub const USER_TESTING_PROOF_SIZE: usize = 42;
pub const AUTOMATED_TESTING_COINBASE_MATURITY: u64 = 3;
pub const USER_TESTING_COINBASE_MATURITY: u64 = 3;
pub const TESTING_CUT_THROUGH_HORIZON: u32 = 70;
pub const TESTING_STATE_SYNC_THRESHOLD: u32 = 20;
pub const TESTING_INITIAL_GRAPH_WEIGHT: u32 = 1;
pub const TESTING_INITIAL_DIFFICULTY: u64 = 1;
pub const TESTING_MAX_BLOCK_WEIGHT: usize = 150;
pub const STUCK_PEER_KICK_TIME: i64 = 2 * 3600 * 1000;
const PEER_EXPIRATION_DAYS: i64 = 7 * 2;
pub const PEER_EXPIRATION_REMOVE_TIME: i64 = PEER_EXPIRATION_DAYS * 24 * 3600;
pub const COMPACTION_CHECK: u64 = DAY_HEIGHT;
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum ChainTypes {
AutomatedTesting,
UserTesting,
Floonet,
Mainnet,
}
impl ChainTypes {
pub fn shortname(&self) -> String {
match *self {
ChainTypes::AutomatedTesting => "auto".to_owned(),
ChainTypes::UserTesting => "user".to_owned(),
ChainTypes::Floonet => "floo".to_owned(),
ChainTypes::Mainnet => "main".to_owned(),
}
}
}
impl Default for ChainTypes {
fn default() -> ChainTypes {
ChainTypes::Mainnet
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum PoWContextTypes {
Cuckoo,
Cuckatoo,
Cuckaroo,
}
lazy_static! {
pub static ref CHAIN_TYPE: RwLock<ChainTypes> =
RwLock::new(ChainTypes::Mainnet);
pub static ref POW_CONTEXT_TYPE: RwLock<PoWContextTypes> =
RwLock::new(PoWContextTypes::Cuckoo);
}
pub fn set_mining_mode(mode: ChainTypes) {
let mut param_ref = CHAIN_TYPE.write();
*param_ref = mode;
}
pub fn create_pow_context<T>(
height: u64,
edge_bits: u8,
proof_size: usize,
max_sols: u32,
) -> Result<Box<dyn PoWContext<T>>, pow::Error>
where
T: EdgeType + 'static,
{
let chain_type = CHAIN_TYPE.read().clone();
match chain_type {
ChainTypes::Mainnet if edge_bits > 29 => new_cuckatoo_ctx(edge_bits, proof_size, max_sols),
ChainTypes::Mainnet if valid_header_version(height, HeaderVersion::new(2)) => {
new_cuckarood_ctx(edge_bits, proof_size)
}
ChainTypes::Mainnet => new_cuckaroo_ctx(edge_bits, proof_size),
ChainTypes::Floonet if edge_bits > 29 => new_cuckatoo_ctx(edge_bits, proof_size, max_sols),
ChainTypes::Floonet if valid_header_version(height, HeaderVersion::new(2)) => {
new_cuckarood_ctx(edge_bits, proof_size)
}
ChainTypes::Floonet => new_cuckaroo_ctx(edge_bits, proof_size),
_ => new_cuckatoo_ctx(edge_bits, proof_size, max_sols),
}
}
pub fn min_edge_bits() -> u8 {
let param_ref = CHAIN_TYPE.read();
match *param_ref {
ChainTypes::AutomatedTesting => AUTOMATED_TESTING_MIN_EDGE_BITS,
ChainTypes::UserTesting => USER_TESTING_MIN_EDGE_BITS,
_ => DEFAULT_MIN_EDGE_BITS,
}
}
pub fn base_edge_bits() -> u8 {
let param_ref = CHAIN_TYPE.read();
match *param_ref {
ChainTypes::AutomatedTesting => AUTOMATED_TESTING_MIN_EDGE_BITS,
ChainTypes::UserTesting => USER_TESTING_MIN_EDGE_BITS,
_ => BASE_EDGE_BITS,
}
}
pub fn proofsize() -> usize {
let param_ref = CHAIN_TYPE.read();
match *param_ref {
ChainTypes::AutomatedTesting => AUTOMATED_TESTING_PROOF_SIZE,
ChainTypes::UserTesting => USER_TESTING_PROOF_SIZE,
_ => PROOFSIZE,
}
}
pub fn coinbase_maturity() -> u64 {
let param_ref = CHAIN_TYPE.read();
match *param_ref {
ChainTypes::AutomatedTesting => AUTOMATED_TESTING_COINBASE_MATURITY,
ChainTypes::UserTesting => USER_TESTING_COINBASE_MATURITY,
_ => COINBASE_MATURITY,
}
}
pub fn initial_block_difficulty() -> u64 {
let param_ref = CHAIN_TYPE.read();
match *param_ref {
ChainTypes::AutomatedTesting => TESTING_INITIAL_DIFFICULTY,
ChainTypes::UserTesting => TESTING_INITIAL_DIFFICULTY,
ChainTypes::Floonet => INITIAL_DIFFICULTY,
ChainTypes::Mainnet => INITIAL_DIFFICULTY,
}
}
pub fn initial_graph_weight() -> u32 {
let param_ref = CHAIN_TYPE.read();
match *param_ref {
ChainTypes::AutomatedTesting => TESTING_INITIAL_GRAPH_WEIGHT,
ChainTypes::UserTesting => TESTING_INITIAL_GRAPH_WEIGHT,
ChainTypes::Floonet => graph_weight(0, SECOND_POW_EDGE_BITS) as u32,
ChainTypes::Mainnet => graph_weight(0, SECOND_POW_EDGE_BITS) as u32,
}
}
pub fn max_block_weight() -> usize {
let param_ref = CHAIN_TYPE.read();
match *param_ref {
ChainTypes::AutomatedTesting => TESTING_MAX_BLOCK_WEIGHT,
ChainTypes::UserTesting => TESTING_MAX_BLOCK_WEIGHT,
ChainTypes::Floonet => MAX_BLOCK_WEIGHT,
ChainTypes::Mainnet => MAX_BLOCK_WEIGHT,
}
}
pub fn cut_through_horizon() -> u32 {
let param_ref = CHAIN_TYPE.read();
match *param_ref {
ChainTypes::AutomatedTesting => TESTING_CUT_THROUGH_HORIZON,
ChainTypes::UserTesting => TESTING_CUT_THROUGH_HORIZON,
_ => CUT_THROUGH_HORIZON,
}
}
pub fn state_sync_threshold() -> u32 {
let param_ref = CHAIN_TYPE.read();
match *param_ref {
ChainTypes::AutomatedTesting => TESTING_STATE_SYNC_THRESHOLD,
ChainTypes::UserTesting => TESTING_STATE_SYNC_THRESHOLD,
_ => STATE_SYNC_THRESHOLD,
}
}
pub fn is_automated_testing_mode() -> bool {
let param_ref = CHAIN_TYPE.read();
ChainTypes::AutomatedTesting == *param_ref
}
pub fn is_user_testing_mode() -> bool {
let param_ref = CHAIN_TYPE.read();
ChainTypes::UserTesting == *param_ref
}
pub fn is_production_mode() -> bool {
let param_ref = CHAIN_TYPE.read();
ChainTypes::Floonet == *param_ref || ChainTypes::Mainnet == *param_ref
}
pub fn is_floonet() -> bool {
let param_ref = CHAIN_TYPE.read();
ChainTypes::Floonet == *param_ref
}
pub fn is_mainnet() -> bool {
let param_ref = CHAIN_TYPE.read();
ChainTypes::Mainnet == *param_ref
}
pub fn get_genesis_nonce() -> u64 {
let param_ref = CHAIN_TYPE.read();
match *param_ref {
ChainTypes::AutomatedTesting => 0,
ChainTypes::UserTesting => 27944,
ChainTypes::Floonet => 0,
ChainTypes::Mainnet => 0,
}
}
pub fn chain_shortname() -> String {
let param_ref = CHAIN_TYPE.read();
param_ref.shortname()
}
pub fn difficulty_data_to_vector<T>(cursor: T) -> Vec<HeaderInfo>
where
T: IntoIterator<Item = HeaderInfo>,
{
let needed_block_count = DIFFICULTY_ADJUST_WINDOW as usize + 1;
let mut last_n: Vec<HeaderInfo> = cursor.into_iter().take(needed_block_count).collect();
let n = last_n.len();
if needed_block_count > n {
let last_ts_delta = if n > 1 {
last_n[0].timestamp - last_n[1].timestamp
} else {
BLOCK_TIME_SEC
};
let last_diff = last_n[0].difficulty;
let mut last_ts = last_n.last().unwrap().timestamp;
for _ in n..needed_block_count {
last_ts = last_ts.saturating_sub(last_ts_delta);
last_n.push(HeaderInfo::from_ts_diff(last_ts, last_diff.clone()));
}
}
last_n.reverse();
last_n
}