thread local chain type vs global chain type (#3327)
* Introduce GLOBAL_CHAIN_TYPE and make CHAIN_TYPE thread_local. This makes testing more explicit and significantly more robust. * set_local_chain_type() in tests * cleanup - weird * get pool tests working with explicit local chain_type config * core tests working with explicit local chain_type * p2p tests working with explicit local chain_type * store tests working * cleanup, feedback
This commit is contained in:
@@ -142,7 +142,7 @@ pub const TESTING_SECOND_HARD_FORK: u64 = 6;
|
||||
/// 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::CHAIN_TYPE.read().clone();
|
||||
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),
|
||||
@@ -383,6 +383,8 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_graph_weight() {
|
||||
global::set_local_chain_type(global::ChainTypes::Mainnet);
|
||||
|
||||
// initial weights
|
||||
assert_eq!(graph_weight(1, 31), 256 * 31);
|
||||
assert_eq!(graph_weight(1, 32), 512 * 32);
|
||||
|
||||
@@ -272,11 +272,13 @@ pub fn genesis_main() -> core::Block {
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::core::hash::Hashed;
|
||||
use crate::global;
|
||||
use crate::ser::{self, ProtocolVersion};
|
||||
use util::ToHex;
|
||||
|
||||
#[test]
|
||||
fn floonet_genesis_hash() {
|
||||
global::set_local_chain_type(global::ChainTypes::Floonet);
|
||||
let gen_hash = genesis_floo().hash();
|
||||
println!("floonet genesis hash: {}", gen_hash.to_hex());
|
||||
let gen_bin = ser::ser_vec(&genesis_floo(), ProtocolVersion(1)).unwrap();
|
||||
@@ -293,6 +295,7 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn mainnet_genesis_hash() {
|
||||
global::set_local_chain_type(global::ChainTypes::Mainnet);
|
||||
let gen_hash = genesis_main().hash();
|
||||
println!("mainnet genesis hash: {}", gen_hash.to_hex());
|
||||
let gen_bin = ser::ser_vec(&genesis_main(), ProtocolVersion(1)).unwrap();
|
||||
|
||||
+57
-49
@@ -27,7 +27,8 @@ use crate::pow::{
|
||||
self, new_cuckaroo_ctx, new_cuckarood_ctx, new_cuckaroom_ctx, new_cuckatoo_ctx, EdgeType,
|
||||
PoWContext,
|
||||
};
|
||||
use util::RwLock;
|
||||
use std::cell::Cell;
|
||||
use util::OneTime;
|
||||
|
||||
/// An enum collecting sets of parameters used throughout the
|
||||
/// code wherever mining is needed. This should allow for
|
||||
@@ -104,7 +105,7 @@ pub const TXHASHSET_ARCHIVE_INTERVAL: u64 = 12 * 60;
|
||||
|
||||
/// Types of chain a server can run with, dictates the genesis block and
|
||||
/// and mining parameters used.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)]
|
||||
pub enum ChainTypes {
|
||||
/// For CI testing
|
||||
AutomatedTesting,
|
||||
@@ -134,31 +135,43 @@ impl Default for ChainTypes {
|
||||
}
|
||||
}
|
||||
|
||||
/// PoW test mining and verifier context
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub enum PoWContextTypes {
|
||||
/// Classic Cuckoo
|
||||
Cuckoo,
|
||||
/// ASIC-friendly Cuckatoo
|
||||
Cuckatoo,
|
||||
/// ASIC-resistant Cuckaroo
|
||||
Cuckaroo,
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
/// The mining parameter mode
|
||||
pub static ref CHAIN_TYPE: RwLock<ChainTypes> =
|
||||
RwLock::new(ChainTypes::Mainnet);
|
||||
|
||||
/// PoW context type to instantiate
|
||||
pub static ref POW_CONTEXT_TYPE: RwLock<PoWContextTypes> =
|
||||
RwLock::new(PoWContextTypes::Cuckoo);
|
||||
/// Global chain_type that must be initialized once on node startup.
|
||||
/// This is accessed via get_chain_type() which allows the global value
|
||||
/// to be overridden on a per-thread basis (for testing).
|
||||
pub static ref GLOBAL_CHAIN_TYPE: OneTime<ChainTypes> = OneTime::new();
|
||||
}
|
||||
|
||||
/// Set the mining mode
|
||||
pub fn set_mining_mode(mode: ChainTypes) {
|
||||
let mut param_ref = CHAIN_TYPE.write();
|
||||
*param_ref = mode;
|
||||
thread_local! {
|
||||
/// Mainnet|Floonet|UserTesting|AutomatedTesting
|
||||
pub static CHAIN_TYPE: Cell<Option<ChainTypes>> = Cell::new(None);
|
||||
}
|
||||
|
||||
/// Set the chain type on a per-thread basis via thread_local storage.
|
||||
pub fn set_local_chain_type(new_type: ChainTypes) {
|
||||
CHAIN_TYPE.with(|chain_type| chain_type.set(Some(new_type)))
|
||||
}
|
||||
|
||||
/// Get the chain type via thread_local, fallback to global chain_type.
|
||||
pub fn get_chain_type() -> ChainTypes {
|
||||
CHAIN_TYPE.with(|chain_type| match chain_type.get() {
|
||||
None => {
|
||||
if GLOBAL_CHAIN_TYPE.is_init() {
|
||||
let chain_type = GLOBAL_CHAIN_TYPE.borrow();
|
||||
set_local_chain_type(chain_type);
|
||||
chain_type
|
||||
} else {
|
||||
panic!("GLOBAL_CHAIN_TYPE and CHAIN_TYPE unset. Consider set_local_chain_type() in tests.");
|
||||
}
|
||||
}
|
||||
Some(chain_type) => chain_type,
|
||||
})
|
||||
}
|
||||
|
||||
/// One time initialization of the global chain_type.
|
||||
/// Will panic if we attempt to re-initialize this (via OneTime).
|
||||
pub fn init_global_chain_type(new_type: ChainTypes) {
|
||||
GLOBAL_CHAIN_TYPE.init(new_type)
|
||||
}
|
||||
|
||||
/// Return either a cuckoo context or a cuckatoo context
|
||||
@@ -172,7 +185,7 @@ pub fn create_pow_context<T>(
|
||||
where
|
||||
T: EdgeType + 'static,
|
||||
{
|
||||
let chain_type = CHAIN_TYPE.read().clone();
|
||||
let chain_type = get_chain_type();
|
||||
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),
|
||||
@@ -201,8 +214,7 @@ where
|
||||
|
||||
/// The minimum acceptable edge_bits
|
||||
pub fn min_edge_bits() -> u8 {
|
||||
let param_ref = CHAIN_TYPE.read();
|
||||
match *param_ref {
|
||||
match get_chain_type() {
|
||||
ChainTypes::AutomatedTesting => AUTOMATED_TESTING_MIN_EDGE_BITS,
|
||||
ChainTypes::UserTesting => USER_TESTING_MIN_EDGE_BITS,
|
||||
_ => DEFAULT_MIN_EDGE_BITS,
|
||||
@@ -213,8 +225,7 @@ pub fn min_edge_bits() -> u8 {
|
||||
/// while the min_edge_bits can be changed on a soft fork, changing
|
||||
/// base_edge_bits is a hard fork.
|
||||
pub fn base_edge_bits() -> u8 {
|
||||
let param_ref = CHAIN_TYPE.read();
|
||||
match *param_ref {
|
||||
match get_chain_type() {
|
||||
ChainTypes::AutomatedTesting => AUTOMATED_TESTING_MIN_EDGE_BITS,
|
||||
ChainTypes::UserTesting => USER_TESTING_MIN_EDGE_BITS,
|
||||
_ => BASE_EDGE_BITS,
|
||||
@@ -223,8 +234,7 @@ pub fn base_edge_bits() -> u8 {
|
||||
|
||||
/// The proofsize
|
||||
pub fn proofsize() -> usize {
|
||||
let param_ref = CHAIN_TYPE.read();
|
||||
match *param_ref {
|
||||
match get_chain_type() {
|
||||
ChainTypes::AutomatedTesting => AUTOMATED_TESTING_PROOF_SIZE,
|
||||
ChainTypes::UserTesting => USER_TESTING_PROOF_SIZE,
|
||||
_ => PROOFSIZE,
|
||||
@@ -233,8 +243,7 @@ pub fn proofsize() -> usize {
|
||||
|
||||
/// Coinbase maturity for coinbases to be spent
|
||||
pub fn coinbase_maturity() -> u64 {
|
||||
let param_ref = CHAIN_TYPE.read();
|
||||
match *param_ref {
|
||||
match get_chain_type() {
|
||||
ChainTypes::AutomatedTesting => AUTOMATED_TESTING_COINBASE_MATURITY,
|
||||
ChainTypes::UserTesting => USER_TESTING_COINBASE_MATURITY,
|
||||
_ => COINBASE_MATURITY,
|
||||
@@ -243,8 +252,7 @@ pub fn coinbase_maturity() -> u64 {
|
||||
|
||||
/// Initial mining difficulty
|
||||
pub fn initial_block_difficulty() -> u64 {
|
||||
let param_ref = CHAIN_TYPE.read();
|
||||
match *param_ref {
|
||||
match get_chain_type() {
|
||||
ChainTypes::AutomatedTesting => TESTING_INITIAL_DIFFICULTY,
|
||||
ChainTypes::UserTesting => TESTING_INITIAL_DIFFICULTY,
|
||||
ChainTypes::Floonet => INITIAL_DIFFICULTY,
|
||||
@@ -253,8 +261,7 @@ pub fn initial_block_difficulty() -> u64 {
|
||||
}
|
||||
/// Initial mining secondary scale
|
||||
pub fn initial_graph_weight() -> u32 {
|
||||
let param_ref = CHAIN_TYPE.read();
|
||||
match *param_ref {
|
||||
match get_chain_type() {
|
||||
ChainTypes::AutomatedTesting => TESTING_INITIAL_GRAPH_WEIGHT,
|
||||
ChainTypes::UserTesting => TESTING_INITIAL_GRAPH_WEIGHT,
|
||||
ChainTypes::Floonet => graph_weight(0, SECOND_POW_EDGE_BITS) as u32,
|
||||
@@ -264,8 +271,7 @@ pub fn initial_graph_weight() -> u32 {
|
||||
|
||||
/// Maximum allowed block weight.
|
||||
pub fn max_block_weight() -> usize {
|
||||
let param_ref = CHAIN_TYPE.read();
|
||||
match *param_ref {
|
||||
match get_chain_type() {
|
||||
ChainTypes::AutomatedTesting => TESTING_MAX_BLOCK_WEIGHT,
|
||||
ChainTypes::UserTesting => TESTING_MAX_BLOCK_WEIGHT,
|
||||
ChainTypes::Floonet => MAX_BLOCK_WEIGHT,
|
||||
@@ -275,8 +281,7 @@ pub fn max_block_weight() -> usize {
|
||||
|
||||
/// Horizon at which we can cut-through and do full local pruning
|
||||
pub fn cut_through_horizon() -> u32 {
|
||||
let param_ref = CHAIN_TYPE.read();
|
||||
match *param_ref {
|
||||
match get_chain_type() {
|
||||
ChainTypes::AutomatedTesting => AUTOMATED_TESTING_CUT_THROUGH_HORIZON,
|
||||
ChainTypes::UserTesting => USER_TESTING_CUT_THROUGH_HORIZON,
|
||||
_ => CUT_THROUGH_HORIZON,
|
||||
@@ -285,8 +290,7 @@ pub fn cut_through_horizon() -> u32 {
|
||||
|
||||
/// Threshold at which we can request a txhashset (and full blocks from)
|
||||
pub fn state_sync_threshold() -> u32 {
|
||||
let param_ref = CHAIN_TYPE.read();
|
||||
match *param_ref {
|
||||
match get_chain_type() {
|
||||
ChainTypes::AutomatedTesting => TESTING_STATE_SYNC_THRESHOLD,
|
||||
ChainTypes::UserTesting => TESTING_STATE_SYNC_THRESHOLD,
|
||||
_ => STATE_SYNC_THRESHOLD,
|
||||
@@ -295,8 +299,7 @@ pub fn state_sync_threshold() -> u32 {
|
||||
|
||||
/// Number of blocks to reuse a txhashset zip for.
|
||||
pub fn txhashset_archive_interval() -> u64 {
|
||||
let param_ref = CHAIN_TYPE.read();
|
||||
match *param_ref {
|
||||
match get_chain_type() {
|
||||
ChainTypes::AutomatedTesting => TESTING_TXHASHSET_ARCHIVE_INTERVAL,
|
||||
ChainTypes::UserTesting => TESTING_TXHASHSET_ARCHIVE_INTERVAL,
|
||||
_ => TXHASHSET_ARCHIVE_INTERVAL,
|
||||
@@ -306,8 +309,11 @@ pub fn txhashset_archive_interval() -> u64 {
|
||||
/// Are we in production mode?
|
||||
/// Production defined as a live public network, testnet[n] or mainnet.
|
||||
pub fn is_production_mode() -> bool {
|
||||
let param_ref = CHAIN_TYPE.read();
|
||||
ChainTypes::Floonet == *param_ref || ChainTypes::Mainnet == *param_ref
|
||||
match get_chain_type() {
|
||||
ChainTypes::Floonet => true,
|
||||
ChainTypes::Mainnet => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Are we in floonet?
|
||||
@@ -315,8 +321,10 @@ pub fn is_production_mode() -> bool {
|
||||
/// as possible to "mainnet" configuration as possible.
|
||||
/// We want to avoid missing any mainnet only code paths.
|
||||
pub fn is_floonet() -> bool {
|
||||
let param_ref = CHAIN_TYPE.read();
|
||||
ChainTypes::Floonet == *param_ref
|
||||
match get_chain_type() {
|
||||
ChainTypes::Floonet => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts an iterator of block difficulty data to more a more manageable
|
||||
|
||||
@@ -252,6 +252,7 @@ mod test {
|
||||
use super::*;
|
||||
use crate::core::transaction::Weighting;
|
||||
use crate::core::verifier_cache::{LruVerifierCache, VerifierCache};
|
||||
use crate::global;
|
||||
use crate::libtx::ProofBuilder;
|
||||
use keychain::{ExtKeychain, ExtKeychainPath};
|
||||
|
||||
@@ -261,6 +262,7 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn blind_simple_tx() {
|
||||
global::set_local_chain_type(global::ChainTypes::AutomatedTesting);
|
||||
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
||||
let builder = ProofBuilder::new(&keychain);
|
||||
let key_id1 = ExtKeychainPath::new(1, 1, 0, 0, 0).to_identifier();
|
||||
@@ -282,6 +284,7 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn blind_simple_tx_with_offset() {
|
||||
global::set_local_chain_type(global::ChainTypes::AutomatedTesting);
|
||||
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
||||
let builder = ProofBuilder::new(&keychain);
|
||||
let key_id1 = ExtKeychainPath::new(1, 1, 0, 0, 0).to_identifier();
|
||||
@@ -303,6 +306,7 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn blind_simpler_tx() {
|
||||
global::set_local_chain_type(global::ChainTypes::AutomatedTesting);
|
||||
let keychain = ExtKeychain::from_random_seed(false).unwrap();
|
||||
let builder = ProofBuilder::new(&keychain);
|
||||
let key_id1 = ExtKeychainPath::new(1, 1, 0, 0, 0).to_identifier();
|
||||
|
||||
+1
-1
@@ -130,7 +130,7 @@ mod test {
|
||||
/// We'll be generating genesis blocks differently
|
||||
#[test]
|
||||
fn genesis_pow() {
|
||||
global::set_mining_mode(ChainTypes::UserTesting);
|
||||
global::set_local_chain_type(ChainTypes::UserTesting);
|
||||
|
||||
let mut b = genesis::genesis_dev();
|
||||
b.header.pow.nonce = 28106;
|
||||
|
||||
@@ -170,6 +170,7 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn cuckaroo19_vectors() {
|
||||
global::set_local_chain_type(global::ChainTypes::Mainnet);
|
||||
let mut ctx = new_impl::<u64>(19, 42);
|
||||
ctx.params.siphash_keys = V1_19_HASH;
|
||||
assert!(ctx.verify(&Proof::new(V1_19_SOL.to_vec())).is_ok());
|
||||
|
||||
@@ -172,6 +172,7 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn cuckarood19_29_vectors() {
|
||||
global::set_local_chain_type(global::ChainTypes::Mainnet);
|
||||
let mut ctx19 = new_impl::<u64>(19, 42);
|
||||
ctx19.params.siphash_keys = V1_19_HASH;
|
||||
assert!(ctx19.verify(&Proof::new(V1_19_SOL.to_vec())).is_ok());
|
||||
|
||||
@@ -165,6 +165,7 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn cuckaroom19_29_vectors() {
|
||||
global::set_local_chain_type(global::ChainTypes::Mainnet);
|
||||
let mut ctx19 = new_impl::<u64>(19, 42);
|
||||
ctx19.params.siphash_keys = V1_19_HASH;
|
||||
assert!(ctx19.verify(&Proof::new(V1_19_SOL.to_vec())).is_ok());
|
||||
|
||||
@@ -367,6 +367,7 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn cuckatoo() {
|
||||
global::set_local_chain_type(global::ChainTypes::Mainnet);
|
||||
let ret = basic_solve::<u32>();
|
||||
if let Err(r) = ret {
|
||||
panic!("basic_solve u32: Error: {}", r);
|
||||
|
||||
@@ -88,10 +88,12 @@ impl Lean {
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::global;
|
||||
use crate::pow::types::PoWContext;
|
||||
|
||||
#[test]
|
||||
fn lean_miner() {
|
||||
global::set_local_chain_type(global::ChainTypes::Mainnet);
|
||||
let nonce = 15465723;
|
||||
let header = [0u8; 84].to_vec(); // with nonce
|
||||
let edge_bits = 19;
|
||||
|
||||
@@ -507,6 +507,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_proof_rw() {
|
||||
global::set_local_chain_type(global::ChainTypes::Mainnet);
|
||||
for edge_bits in 10..63 {
|
||||
let mut proof = Proof::new(gen_proof(edge_bits as u32));
|
||||
proof.edge_bits = edge_bits;
|
||||
|
||||
Reference in New Issue
Block a user