Skip to content

Commit

Permalink
Added minimum target difficulty (+ validation) and chain ID
Browse files Browse the repository at this point in the history
  • Loading branch information
ksrichard committed Sep 9, 2024
1 parent c0881a2 commit daa2676
Show file tree
Hide file tree
Showing 12 changed files with 117 additions and 41 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ hex = "0.4.3"
serde_json = "1.0.122"
hickory-resolver = { version = "*", features = ["dns-over-rustls"] }
convert_case = "0.6.0"
lazy_static = "1.5.0"

[package.metadata.cargo-machete]
ignored = ["log4rs"]
2 changes: 2 additions & 0 deletions src/server/grpc/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ use thiserror::Error;
pub enum Error {
#[error("Tonic error: {0}")]
Tonic(#[from] TonicError),
#[error("No consensus constants found")]
NoConsensusConstants,
#[error("Shutdown")]
Shutdown,
}
Expand Down
24 changes: 23 additions & 1 deletion src/server/grpc/p2pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ use minotari_app_grpc::tari_rpc::{
base_node_client::BaseNodeClient, sha_p2_pool_server::ShaP2Pool, GetNewBlockRequest, GetNewBlockResponse,
GetNewBlockTemplateWithCoinbasesRequest, NewBlockTemplateRequest, SubmitBlockRequest, SubmitBlockResponse,
};
use tari_common::configuration::Network;
use tari_common_types::types::FixedHash;
use tari_core::consensus;
use tari_core::consensus::ConsensusManager;
use tari_core::proof_of_work::randomx_factory::RandomXFactory;
use tari_core::proof_of_work::{randomx_difficulty, sha3x_difficulty, PowAlgorithm};
Expand All @@ -35,6 +37,21 @@ use crate::{

const LOG_TARGET: &str = "p2pool::server::grpc::p2pool";

pub fn min_difficulty(pow: PowAlgorithm) -> Result<u64, Error> {
let network = Network::get_current_or_user_setting_or_default();
let consensus_constants = match network {
Network::MainNet => consensus::ConsensusConstants::mainnet(),
Network::StageNet => consensus::ConsensusConstants::stagenet(),
Network::NextNet => consensus::ConsensusConstants::nextnet(),
Network::LocalNet => consensus::ConsensusConstants::localnet(),
Network::Igor => consensus::ConsensusConstants::igor(),
Network::Esmeralda => consensus::ConsensusConstants::esmeralda(),
};
let consensus_constants = consensus_constants.first().ok_or(Error::NoConsensusConstants)?;

Ok(consensus_constants.min_pow_difficulty(pow).as_u64())
}

/// P2Pool specific gRPC service to provide `get_new_block` and `submit_block` functionalities.
pub struct ShaP2PoolGrpc<S>
where
Expand Down Expand Up @@ -183,7 +200,12 @@ where
.await
.insert(height, miner_data.target_difficulty);
}
let target_difficulty = miner_data.target_difficulty / SHARE_COUNT;
let min_difficulty =
min_difficulty(pow_algo).map_err(|_| Status::internal("failed to get minimum difficulty"))?;
let mut target_difficulty = miner_data.target_difficulty / SHARE_COUNT;
if target_difficulty < min_difficulty {
target_difficulty = min_difficulty;
}
if let Some(mut miner_data) = response.miner_data {
miner_data.target_difficulty = target_difficulty;
response.miner_data = Some(miner_data);
Expand Down
4 changes: 0 additions & 4 deletions src/server/http/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

use crate::server::http::stats::cache::StatsCache;
use crate::server::http::stats::handlers;
use crate::server::http::stats::models::{BlockStats, EstimatedEarnings, Stats, TribeDetails};
use crate::server::http::{health, version};
use crate::server::p2p::peer_store::PeerStore;
use crate::server::p2p::Tribe;
Expand All @@ -13,12 +12,9 @@ use axum::routing::get;
use axum::Router;
use log::info;
use std::sync::Arc;
use std::time::Duration;
use tari_shutdown::ShutdownSignal;
use thiserror::Error;
use tokio::io;
use tokio::sync::{Mutex, RwLock, RwLockWriteGuard};
use tokio::time::Instant;

const LOG_TARGET: &str = "p2pool::server::stats";

Expand Down
18 changes: 9 additions & 9 deletions src/server/http/stats/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,19 @@ impl CachedStats {
pub fn new(stats: Stats, last_update: Instant) -> Self {
Self { stats, last_update }
}

pub fn stats(&self) -> &Stats {
&self.stats
}

pub fn last_update(&self) -> Instant {
self.last_update
}
}

pub struct StatsCache {
ttl: Duration,
stats: Arc<RwLock<Option<CachedStats>>>,
}

impl Default for StatsCache {
fn default() -> Self {
Self::new(Duration::from_secs(10))
}
}

impl StatsCache {
pub fn new(ttl: Duration) -> Self {
Self {
Expand All @@ -52,7 +50,9 @@ impl StatsCache {

pub async fn stats(&self) -> Option<Stats> {
let lock = self.stats.read().await;
if lock.is_some() && Instant::now().duration_since(lock.as_ref()?.last_update) > self.ttl {
let last_update = lock.as_ref()?.last_update;
if lock.is_some() && Instant::now().duration_since(last_update) > self.ttl {
drop(lock);
let mut lock = self.stats.write().await;
*lock = None;
return None;
Expand Down
3 changes: 2 additions & 1 deletion src/server/p2p/network.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ use tokio::{
};

use crate::server::p2p::messages::LocalShareChainSyncRequest;
use crate::sharechain::block::CURRENT_CHAIN_ID;
use crate::{
server::{
config,
Expand Down Expand Up @@ -392,7 +393,7 @@ where
/// blocks and peers with different Tari networks and the given tribe name.
fn tribe_topic(tribe: &Tribe, topic: &str) -> String {
let network = Network::get_current_or_user_setting_or_default().as_key_str();
format!("{network}_{tribe}_{topic}")
format!("{network}_{}_{tribe}_{topic}", CURRENT_CHAIN_ID.clone())
}

/// Subscribing to a gossipsub topic.
Expand Down
3 changes: 1 addition & 2 deletions src/server/p2p/peer_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@

use itertools::Itertools;
use libp2p::PeerId;
use log::{debug, info, warn};
use log::{debug, warn};
use moka::future::{Cache, CacheBuilder};
use std::ops::Add;
use std::{
sync::RwLock,
time::{Duration, Instant},
Expand Down
3 changes: 1 addition & 2 deletions src/server/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
use log::{error, info};
use minotari_app_grpc::tari_rpc::{base_node_server::BaseNodeServer, sha_p2_pool_server::ShaP2PoolServer};
use std::sync::atomic::AtomicBool;
use std::time::Duration;
use std::{
net::{AddrParseError, SocketAddr},
str::FromStr,
Expand Down Expand Up @@ -113,7 +112,7 @@ where
p2pool_server = Some(ShaP2PoolServer::new(p2pool_grpc_service));
}

let http_stats_cache = Arc::new(StatsCache::new(Duration::from_secs(10)));
let http_stats_cache = Arc::new(StatsCache::default());

let stats_server = if config.http_server.enabled {
Some(Arc::new(HttpServer::new(
Expand Down
19 changes: 17 additions & 2 deletions src/sharechain/block.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,34 @@
// Copyright 2024 The Tari Project
// SPDX-License-Identifier: BSD-3-Clause

use crate::impl_conversions;
use crate::sharechain::CHAIN_ID;
use blake2::Blake2b;
use digest::consts::U32;
use lazy_static::lazy_static;
use serde::{Deserialize, Serialize};
use tari_common::configuration::Network;
use tari_common_types::{tari_address::TariAddress, types::BlockHash};
use tari_core::blocks::genesis_block::get_genesis_block;
use tari_core::{
blocks::{BlockHeader, BlocksHashDomain},
consensus::DomainSeparatedConsensusHasher,
};
use tari_utilities::epoch_time::EpochTime;

use crate::impl_conversions;
use tari_utilities::hex::Hex;

lazy_static! {
pub static ref CURRENT_CHAIN_ID: String = {
let network = Network::get_current_or_user_setting_or_default();
let network_genesis_block = get_genesis_block(network);
let network_genesis_block_hash = network_genesis_block.block().header.hash().to_hex();
format!("{network_genesis_block_hash}_{CHAIN_ID}")
};
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct Block {
chain_id: String,
hash: BlockHash,
timestamp: EpochTime,
prev_hash: BlockHash,
Expand Down Expand Up @@ -92,6 +106,7 @@ impl BlockBuilder {
pub fn new() -> Self {
Self {
block: Block {
chain_id: CURRENT_CHAIN_ID.clone(),
hash: Default::default(),
timestamp: EpochTime::now(),
prev_hash: Default::default(),
Expand Down
76 changes: 56 additions & 20 deletions src/sharechain/in_memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ use std::slice::Iter;
use std::str::FromStr;
use std::{collections::HashMap, sync::Arc};

use crate::server::grpc::p2pool::min_difficulty;
use crate::sharechain::{
error::{BlockConvertError, Error},
Block, BlockValidationParams, ShareChain, ShareChainResult, SubmitBlockResult, ValidateBlockResult, BLOCKS_WINDOW,
MAX_BLOCKS_COUNT, SHARE_COUNT,
};
use async_trait::async_trait;
use itertools::Itertools;
use log::{debug, error, info, warn};
Expand All @@ -14,16 +20,10 @@ use num::{BigUint, Integer, Zero};
use tari_common_types::tari_address::TariAddress;
use tari_common_types::types::BlockHash;
use tari_core::blocks;
use tari_core::proof_of_work::{randomx_difficulty, sha3x_difficulty, PowAlgorithm};
use tari_core::proof_of_work::{randomx_difficulty, sha3x_difficulty, Difficulty, PowAlgorithm};
use tari_utilities::{epoch_time::EpochTime, hex::Hex};
use tokio::sync::{RwLock, RwLockWriteGuard};

use crate::sharechain::{
error::{BlockConvertError, Error},
Block, BlockValidationParams, ShareChain, ShareChainResult, SubmitBlockResult, ValidateBlockResult, BLOCKS_WINDOW,
MAX_BLOCKS_COUNT, SHARE_COUNT,
};

const LOG_TARGET: &str = "p2pool::sharechain::in_memory";

pub struct InMemoryShareChain {
Expand Down Expand Up @@ -115,16 +115,16 @@ impl InMemoryShareChain {
params.genesis_block_hash(),
params.consensus_manager(),
)
.map_err(Error::RandomXDifficulty)?;
.map_err(Error::RandomXDifficulty)?;
Ok(difficulty.as_u64())
} else {
Ok(0)
}
}
},
PowAlgorithm::Sha3x => {
let difficulty = sha3x_difficulty(block.original_block_header()).map_err(Error::Difficulty)?;
Ok(difficulty.as_u64())
}
},
}
}

Expand Down Expand Up @@ -167,6 +167,28 @@ impl InMemoryShareChain {
result
}

fn validate_min_difficulty(
&self,
pow: PowAlgorithm,
curr_difficulty: Difficulty,
) -> ShareChainResult<ValidateBlockResult> {
match min_difficulty(pow) {
Ok(min_difficulty) => {
if curr_difficulty.as_u64() < min_difficulty {
warn!(target: LOG_TARGET, "[{:?}] ❌ Too low difficulty!", self.pow_algo);
return Ok(ValidateBlockResult::new(false, false));
}
},
Err(error) => {
warn!(target: LOG_TARGET, "[{:?}] ❌ Can't get min difficulty!", self.pow_algo);
debug!(target: LOG_TARGET, "[{:?}] ❌ Can't get min difficulty: {error:?}", self.pow_algo);
return Ok(ValidateBlockResult::new(false, false));
},
}

Ok(ValidateBlockResult::new(true, false))
}

/// Validating a new block.
async fn validate_block(
&self,
Expand Down Expand Up @@ -204,29 +226,43 @@ impl InMemoryShareChain {
match block.original_block_header().pow.pow_algo {
PowAlgorithm::RandomX => match params {
Some(params) => {
if let Err(error) = randomx_difficulty(
match randomx_difficulty(
block.original_block_header(),
params.random_x_factory(),
params.genesis_block_hash(),
params.consensus_manager(),
) {
warn!(target: LOG_TARGET, "[{:?}] ❌ Invalid PoW!", self.pow_algo);
debug!(target: LOG_TARGET, "[{:?}] Failed to calculate RandomX difficulty: {error:?}", self.pow_algo);
return Ok(ValidateBlockResult::new(false, false));
Ok(curr_difficulty) => {
let result = self.validate_min_difficulty(PowAlgorithm::RandomX, curr_difficulty)?;
if !result.valid {
return Ok(result);
}
},
Err(error) => {
warn!(target: LOG_TARGET, "[{:?}] ❌ Invalid PoW!", self.pow_algo);
debug!(target: LOG_TARGET, "[{:?}] Failed to calculate RandomX difficulty: {error:?}", self.pow_algo);
return Ok(ValidateBlockResult::new(false, false));
},
}
}
},
None => {
error!(target: LOG_TARGET, "[{:?}] ❌ Cannot calculate PoW! Missing validation parameters!", self.pow_algo);
return Ok(ValidateBlockResult::new(false, false));
}
},
},
PowAlgorithm::Sha3x => {
if let Err(error) = sha3x_difficulty(block.original_block_header()) {
PowAlgorithm::Sha3x => match sha3x_difficulty(block.original_block_header()) {
Ok(curr_difficulty) => {
let result = self.validate_min_difficulty(PowAlgorithm::Sha3x, curr_difficulty)?;
if !result.valid {
return Ok(result);
}
},
Err(error) => {
warn!(target: LOG_TARGET, "[{:?}] ❌ Invalid PoW!", self.pow_algo);
debug!(target: LOG_TARGET, "[{:?}] Failed to calculate SHA3x difficulty: {error:?}", self.pow_algo);
return Ok(ValidateBlockResult::new(false, false));
}
}
},
},
}

// TODO: check here for miners
Expand Down
4 changes: 4 additions & 0 deletions src/sharechain/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ use tari_common_types::types::FixedHash;
use tari_core::consensus::ConsensusManager;
use tari_core::proof_of_work::randomx_factory::RandomXFactory;

/// Chain ID is an identifier which makes sure we apply the same rules to blocks.
/// Note: This must be updated when new logic applied to blocks handling.
pub const CHAIN_ID: usize = 1;

/// How many blocks to keep overall.
pub const MAX_BLOCKS_COUNT: usize = 240;

Expand Down

0 comments on commit daa2676

Please sign in to comment.