diff --git a/src/cli/args.rs b/src/cli/args.rs index cbfdce3..6c53119 100644 --- a/src/cli/args.rs +++ b/src/cli/args.rs @@ -125,6 +125,12 @@ pub(crate) struct StartArgs { pub randomx_disabled: bool, #[arg(long, default_value_t = false)] pub sha3x_disabled: bool, + + #[arg(long, value_name = "bt")] + pub block_time: Option, + + #[arg(long, value_name = "sw")] + pub share_window: Option, } #[derive(Clone, Parser, Debug)] diff --git a/src/cli/commands/util.rs b/src/cli/commands/util.rs index 077cef1..3a7a40a 100644 --- a/src/cli/commands/util.rs +++ b/src/cli/commands/util.rs @@ -53,6 +53,14 @@ pub async fn server( config_builder.with_p2p_port(p2p_port); } + if let Some(block_time) = args.block_time { + config_builder.with_block_time(block_time); + } + + if let Some(share_window) = args.share_window { + config_builder.with_share_window(share_window); + } + config_builder.with_squad(Squad::from(args.squad.clone())); // set default tari network specific seed peer address @@ -129,6 +137,7 @@ genesis_block_hash.to_hex()); let stats_collector = StatsCollector::new(shutdown_signal.clone(), stats_rx); let share_chain_sha3x = InMemoryShareChain::new( + config.clone(), PowAlgorithm::Sha3x, None, consensus_manager.clone(), @@ -137,6 +146,7 @@ genesis_block_hash.to_hex()); )?; let coinbase_extras_random_x = Arc::new(RwLock::new(HashMap::>::new())); let share_chain_random_x = InMemoryShareChain::new( + config.clone(), PowAlgorithm::RandomX, Some(block_validation_params.clone()), consensus_manager, diff --git a/src/server/config.rs b/src/server/config.rs index 40d3900..e941ebb 100644 --- a/src/server/config.rs +++ b/src/server/config.rs @@ -21,6 +21,8 @@ pub struct Config { pub network_silence_delay: u64, pub max_relay_circuits: Option, pub max_relay_circuits_per_peer: Option, + pub block_time: u64, + pub share_window: u64, } impl Default for Config { @@ -37,6 +39,8 @@ impl Default for Config { network_silence_delay: 300, max_relay_circuits: None, max_relay_circuits_per_peer: None, + block_time: 10, + share_window: 2160, } } } @@ -182,6 +186,16 @@ impl ConfigBuilder { self } + pub fn with_block_time(&mut self, config: u64) -> &mut Self { + self.config.block_time = config; + self + } + + pub fn with_share_window(&mut self, config: u64) -> &mut Self { + self.config.share_window = config; + self + } + pub fn build(&self) -> Config { self.config.clone() } diff --git a/src/sharechain/in_memory.rs b/src/sharechain/in_memory.rs index 04b0ba5..cbefd36 100644 --- a/src/sharechain/in_memory.rs +++ b/src/sharechain/in_memory.rs @@ -21,16 +21,9 @@ use tari_core::{ use tari_utilities::{epoch_time::EpochTime, hex::Hex}; use tokio::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard}; -use super::{ - MAIN_REWARD_SHARE, - MAX_BLOCKS_COUNT, - MIN_RANDOMX_DIFFICULTY, - MIN_SHA3X_DIFFICULTY, - SHARE_WINDOW, - UNCLE_REWARD_SHARE, -}; +use super::{MAIN_REWARD_SHARE, MIN_RANDOMX_DIFFICULTY, MIN_SHA3X_DIFFICULTY, UNCLE_REWARD_SHARE}; use crate::{ - server::{http::stats_collector::StatsBroadcastClient, PROTOCOL_VERSION}, + server::{http::stats_collector::StatsBroadcastClient, Config, PROTOCOL_VERSION}, sharechain::{ error::{ShareChainError, ValidationError}, p2block::{P2Block, P2BlockBuilder}, @@ -58,11 +51,13 @@ pub(crate) struct InMemoryShareChain { consensus_manager: ConsensusManager, coinbase_extras: Arc>>>, stat_client: StatsBroadcastClient, + config: Config, } #[allow(dead_code)] impl InMemoryShareChain { pub fn new( + config: Config, pow_algo: PowAlgorithm, block_validation_params: Option>, consensus_manager: ConsensusManager, @@ -74,12 +69,17 @@ impl InMemoryShareChain { } Ok(Self { - p2_chain: Arc::new(RwLock::new(P2Chain::new_empty(MAX_BLOCKS_COUNT, SHARE_WINDOW))), + p2_chain: Arc::new(RwLock::new(P2Chain::new_empty( + config.share_window * 2, + config.share_window, + config.block_time, + ))), pow_algo, block_validation_params, consensus_manager, coinbase_extras, stat_client, + config, }) } @@ -198,7 +198,7 @@ impl InMemoryShareChain { let tip_height = p2_chain.get_tip().unwrap().height; // We keep more blocks than the share window, but its only to validate the share window. If a block comes in // older than the share window is way too old for us to care about. - if block.height < tip_height.saturating_sub(SHARE_WINDOW as u64) && !syncing { + if block.height < tip_height.saturating_sub(self.config.share_window) && !syncing { return Err(ShareChainError::BlockValidation( "Block is older than share window".to_string(), )); @@ -257,7 +257,7 @@ impl InMemoryShareChain { }; // we want to count 1 short,as the final share will be for this node - let stop_height = tip_level.height.saturating_sub(SHARE_WINDOW as u64 - 1); + let stop_height = tip_level.height.saturating_sub(self.config.share_window - 1); let mut cur_block = tip_level .blocks .get(&tip_level.chain_block) @@ -800,6 +800,7 @@ pub mod test { let (stats_tx, _) = tokio::sync::broadcast::channel(1000); let stats_broadcast_client = StatsBroadcastClient::new(stats_tx); InMemoryShareChain::new( + Config::default(), PowAlgorithm::Sha3x, None, consensus_manager, @@ -823,6 +824,7 @@ pub mod test { let (stats_tx, _) = tokio::sync::broadcast::channel(1000); let stats_broadcast_client = StatsBroadcastClient::new(stats_tx); let share_chain = InMemoryShareChain::new( + Config::default(), PowAlgorithm::Sha3x, None, consensus_manager, @@ -872,6 +874,7 @@ pub mod test { let static_coinbase_extra = Vec::new(); let stats_broadcast_client = StatsBroadcastClient::new(stats_tx); let share_chain = InMemoryShareChain::new( + Config::default(), PowAlgorithm::Sha3x, None, consensus_manager, @@ -925,6 +928,7 @@ pub mod test { let stats_broadcast_client = StatsBroadcastClient::new(stats_tx); let static_coinbase_extra = Vec::new(); let share_chain = InMemoryShareChain::new( + Config::default(), PowAlgorithm::Sha3x, None, consensus_manager, @@ -1083,6 +1087,7 @@ pub mod test { let (stats_tx, _) = tokio::sync::broadcast::channel(1000); let stats_broadcast_client = StatsBroadcastClient::new(stats_tx); let share_chain = InMemoryShareChain::new( + Config::default(), PowAlgorithm::Sha3x, None, consensus_manager, diff --git a/src/sharechain/mod.rs b/src/sharechain/mod.rs index 467c39d..93708f4 100644 --- a/src/sharechain/mod.rs +++ b/src/sharechain/mod.rs @@ -36,20 +36,12 @@ use crate::sharechain::{error::ShareChainError, p2block::P2Block, p2chain::Chain /// Note: This must be updated when new logic applied to blocks handling. pub const CHAIN_ID: usize = 2; -/// How many blocks to keep overall. -pub const MAX_BLOCKS_COUNT: usize = 4320; - -/// How many blocks are used to calculate current shares to be paid out. -pub const SHARE_WINDOW: usize = 2160; - /// Using 5 and 4 m,eans uncles get 80% of the reward pub const MAIN_REWARD_SHARE: u64 = 5; pub const UNCLE_REWARD_SHARE: u64 = 4; pub const DIFFICULTY_ADJUSTMENT_WINDOW: usize = 90; -pub const BLOCK_TARGET_TIME: u64 = 10; - pub const MIN_RANDOMX_DIFFICULTY: u64 = 1_000; // 1 Khs every ten seconds pub const MIN_SHA3X_DIFFICULTY: u64 = 100_000_000; // 1 Mhs every ten seconds diff --git a/src/sharechain/p2chain.rs b/src/sharechain/p2chain.rs index afee7f5..92d5d84 100644 --- a/src/sharechain/p2chain.rs +++ b/src/sharechain/p2chain.rs @@ -38,15 +38,14 @@ use crate::sharechain::{ in_memory::MAX_UNCLE_AGE, p2block::P2Block, p2chain_level::P2ChainLevel, - BLOCK_TARGET_TIME, DIFFICULTY_ADJUSTMENT_WINDOW, }; const LOG_TARGET: &str = "tari::p2pool::sharechain::chain"; // this is the max we are allowed to go over the size -pub const SAFETY_MARGIN: usize = 20; +pub const SAFETY_MARGIN: u64 = 20; // this is the max extra lenght the chain can grow in front of our tip -pub const MAX_EXTRA_SYNC: usize = 2000; +pub const MAX_EXTRA_SYNC: u64 = 2000; // this is the max bocks we store that are more than MAX_EXTRA_SYNC in front of our tip pub const MAX_SYNC_STORE: usize = 200; // this is the max missing parents we allow to process before we stop processing a chain and wait for more parents @@ -126,10 +125,11 @@ impl Display for ChainAddResult { } pub struct P2Chain { + pub block_time: u64, pub cached_shares: Option)>>, pub(crate) levels: VecDeque, - total_size: usize, - share_window: usize, + total_size: u64, + share_window: u64, current_tip: u64, pub lwma: LinearWeightedMovingAverage, sync_store: HashMap>, @@ -178,11 +178,12 @@ impl P2Chain { .get_mut(usize::try_from(index?).expect("32 bit systems not supported")) } - pub fn new_empty(total_size: usize, share_window: usize) -> Self { - let levels = VecDeque::with_capacity(total_size + 1); - let lwma = LinearWeightedMovingAverage::new(DIFFICULTY_ADJUSTMENT_WINDOW, BLOCK_TARGET_TIME) - .expect("Failed to create LWMA"); + pub fn new_empty(total_size: u64, share_window: u64, block_time: u64) -> Self { + let levels = VecDeque::with_capacity(usize::try_from(total_size).expect("Only 64bit supported") + 1); + let lwma = + LinearWeightedMovingAverage::new(DIFFICULTY_ADJUSTMENT_WINDOW, block_time).expect("Failed to create LWMA"); Self { + block_time, cached_shares: None, levels, total_size, @@ -198,12 +199,12 @@ impl P2Chain { let first_index = self.levels.back().map(|level| level.height).unwrap_or(0); let current_chain_length = self.current_tip.saturating_sub(first_index); // let see if we are the limit for the current chain - if current_chain_length >= (self.total_size + SAFETY_MARGIN) as u64 { + if current_chain_length >= self.total_size + SAFETY_MARGIN { return true; } // lets check to see if we are over the max sync length // Ideally this limit should not be reached ever - self.levels.len() >= self.total_size + SAFETY_MARGIN + MAX_EXTRA_SYNC + self.levels.len() as u64 >= self.total_size + SAFETY_MARGIN + MAX_EXTRA_SYNC } fn set_new_tip(&mut self, new_height: u64, hash: FixedHash) -> Result<(), ShareChainError> { @@ -407,7 +408,7 @@ impl P2Chain { new_tip.set_new_tip(hash, new_block_height); // we need to reorg the chain // lets start by resetting the lwma - self.lwma = LinearWeightedMovingAverage::new(DIFFICULTY_ADJUSTMENT_WINDOW, BLOCK_TARGET_TIME) + self.lwma = LinearWeightedMovingAverage::new(DIFFICULTY_ADJUSTMENT_WINDOW, self.block_time) .expect("Failed to create LWMA"); self.lwma.add_front(block.timestamp, block.target_difficulty()); let chain_height = self @@ -641,7 +642,7 @@ impl P2Chain { // lets check where this is, do we need to store it in the sync store let first_index = self.levels.back().map(|level| level.height).unwrap_or(0); - if new_block_height >= first_index + (self.total_size + SAFETY_MARGIN + MAX_EXTRA_SYNC) as u64 { + if new_block_height >= first_index + self.total_size + SAFETY_MARGIN + MAX_EXTRA_SYNC { if self.sync_store.len() > MAX_SYNC_STORE { // lets remove the oldest block if let Some(hash) = self.sync_store_fifo_list.pop_back() { @@ -802,7 +803,7 @@ mod test { #[test] fn test_only_keeps_size() { - let mut chain = P2Chain::new_empty(10, 5); + let mut chain = P2Chain::new_empty(10, 5, 10); let mut tari_block = Block::new(BlockHeader::new(0), AggregateBody::empty()); let mut prev_block = None; for i in 0..41 { @@ -835,7 +836,7 @@ mod test { #[test] fn get_tips() { - let mut chain = P2Chain::new_empty(10, 5); + let mut chain = P2Chain::new_empty(10, 5, 10); let mut prev_block = None; let mut tari_block = Block::new(BlockHeader::new(0), AggregateBody::empty()); @@ -863,7 +864,7 @@ mod test { fn test_does_not_set_tip_unless_full_chain() { // we have a window of 5, meaing that we need 5 valid blocks // if we dont start at 0, we need a chain of at least 6 blocks - let mut chain = P2Chain::new_empty(10, 5); + let mut chain = P2Chain::new_empty(10, 5, 10); let mut prev_block = None; let mut tari_block = Block::new(BlockHeader::new(0), AggregateBody::empty()); @@ -909,7 +910,7 @@ mod test { // to test this properly we need 6 blocks in the chain, and not use 0 as zero will always be valid and counter // as chain start block height 2 will only be valid if it has parents aka block 1, so we need share // window + 1 blocks in chain-- - let mut chain = P2Chain::new_empty(10, 5); + let mut chain = P2Chain::new_empty(10, 5, 10); let mut prev_block = None; let mut tari_block = Block::new(BlockHeader::new(0), AggregateBody::empty()); @@ -952,7 +953,7 @@ mod test { // to test this properly we need 6 blocks in the chain, and not use 0 as zero will always be valid and counter // as chain start block height 2 will only be valid if it has parents aka block 1, so we need share // window + 1 blocks in chain-- - let mut chain = P2Chain::new_empty(20, 10); + let mut chain = P2Chain::new_empty(20, 10, 10); let mut prev_block = None; let mut tari_block = Block::new(BlockHeader::new(0), AggregateBody::empty()); @@ -993,7 +994,7 @@ mod test { // to test this properly we need 6 blocks in the chain, and not use 0 as zero will always be valid and counter // as chain start block height 2 will only be valid if it has parents aka block 1, so we need share // window + 1 blocks in chain-- - let mut chain = P2Chain::new_empty(10, 5); + let mut chain = P2Chain::new_empty(10, 5, 10); let mut prev_block = None; let mut tari_block = Block::new(BlockHeader::new(0), AggregateBody::empty()); @@ -1060,7 +1061,7 @@ mod test { #[test] fn test_dont_set_tip_on_single_high_height() { - let mut chain = P2Chain::new_empty(10, 5); + let mut chain = P2Chain::new_empty(10, 5, 10); let mut prev_block = None; let mut tari_block = Block::new(BlockHeader::new(0), AggregateBody::empty()); @@ -1136,7 +1137,7 @@ mod test { #[test] fn get_parent() { - let mut chain = P2Chain::new_empty(10, 5); + let mut chain = P2Chain::new_empty(10, 5, 10); let mut prev_block = None; let mut tari_block = Block::new(BlockHeader::new(0), AggregateBody::empty()); @@ -1170,7 +1171,7 @@ mod test { #[test] fn add_blocks_to_chain_happy_path() { - let mut chain = P2Chain::new_empty(10, 5); + let mut chain = P2Chain::new_empty(10, 5, 10); let mut timestamp = EpochTime::now(); let mut prev_block = None; @@ -1201,7 +1202,7 @@ mod test { #[test] fn add_blocks_to_chain_small_reorg() { - let mut chain = P2Chain::new_empty(10, 5); + let mut chain = P2Chain::new_empty(10, 5, 10); let mut timestamp = EpochTime::now(); let mut prev_block = None; @@ -1296,7 +1297,7 @@ mod test { #[test] fn calculate_total_difficulty_correctly() { - let mut chain = P2Chain::new_empty(10, 5); + let mut chain = P2Chain::new_empty(10, 5, 10); let mut timestamp = EpochTime::now(); let mut prev_block = None; @@ -1325,7 +1326,7 @@ mod test { #[test] fn calculate_total_difficulty_correctly_with_uncles() { - let mut chain = P2Chain::new_empty(10, 5); + let mut chain = P2Chain::new_empty(10, 5, 10); let mut timestamp = EpochTime::now(); let mut prev_block = None; @@ -1377,7 +1378,7 @@ mod test { #[test] fn calculate_total_difficulty_correctly_with_wrapping_blocks() { - let mut chain = P2Chain::new_empty(10, 5); + let mut chain = P2Chain::new_empty(10, 5, 10); let mut timestamp = EpochTime::now(); let mut prev_block = None; @@ -1429,7 +1430,7 @@ mod test { #[test] fn reorg_with_uncles() { - let mut chain = P2Chain::new_empty(10, 5); + let mut chain = P2Chain::new_empty(10, 5, 10); let mut timestamp = EpochTime::now(); let mut prev_block = None; @@ -1535,7 +1536,7 @@ mod test { #[test] fn rerog_less_than_share_window() { - let mut chain = P2Chain::new_empty(20, 15); + let mut chain = P2Chain::new_empty(20, 15, 20); let mut prev_block = None; let mut tari_block = Block::new(BlockHeader::new(0), AggregateBody::empty()); @@ -1597,7 +1598,7 @@ mod test { #[test] fn rests_levels_after_reorg() { - let mut chain = P2Chain::new_empty(20, 15); + let mut chain = P2Chain::new_empty(20, 15, 20); let mut prev_block = None; let mut tari_block = Block::new(BlockHeader::new(0), AggregateBody::empty()); @@ -1652,7 +1653,7 @@ mod test { #[test] fn difficulty_go_up() { - let mut chain = P2Chain::new_empty(10, 5); + let mut chain = P2Chain::new_empty(10, 5, 10); let mut prev_block = None; let mut tari_block = Block::new(BlockHeader::new(0), AggregateBody::empty()); @@ -1691,7 +1692,7 @@ mod test { } #[test] fn difficulty_go_down() { - let mut chain = P2Chain::new_empty(10, 5); + let mut chain = P2Chain::new_empty(10, 5, 10); let mut prev_block = None; let mut tari_block = Block::new(BlockHeader::new(0), AggregateBody::empty()); @@ -1734,7 +1735,7 @@ mod test { // This test adds a block to the tip, and then adds second block, // but has an uncle that is not in the chain. This test checks that // the tip is not set to the new block, because the uncle is missing. - let mut chain = P2Chain::new_empty(10, 5); + let mut chain = P2Chain::new_empty(10, 5, 10); let prev_block = None; @@ -1767,7 +1768,7 @@ mod test { #[test] fn test_only_reorg_to_chain_if_it_is_verified() { - let mut chain = P2Chain::new_empty(10, 5); + let mut chain = P2Chain::new_empty(10, 5, 10); let prev_block = None; let block = P2BlockBuilder::new(prev_block.as_ref())