mirror of
https://github.com/Cuprate/cuprate.git
synced 2025-01-09 04:20:01 +00:00
cache sorted long and short term block weights
This commit is contained in:
parent
9471ca5d6a
commit
f025513950
3 changed files with 84 additions and 36 deletions
|
@ -24,7 +24,7 @@ use monero_consensus::{
|
||||||
mod tx_pool;
|
mod tx_pool;
|
||||||
|
|
||||||
const MAX_BLOCKS_IN_RANGE: u64 = 1000;
|
const MAX_BLOCKS_IN_RANGE: u64 = 1000;
|
||||||
const MAX_BLOCKS_HEADERS_IN_RANGE: u64 = 250;
|
const MAX_BLOCKS_HEADERS_IN_RANGE: u64 = 500;
|
||||||
|
|
||||||
/// Calls for a batch of blocks, returning the response and the time it took.
|
/// Calls for a batch of blocks, returning the response and the time it took.
|
||||||
async fn call_batch<D: Database>(
|
async fn call_batch<D: Database>(
|
||||||
|
@ -229,13 +229,14 @@ async fn main() {
|
||||||
let rpc_config = RpcConfig::new(MAX_BLOCKS_IN_RANGE, MAX_BLOCKS_HEADERS_IN_RANGE);
|
let rpc_config = RpcConfig::new(MAX_BLOCKS_IN_RANGE, MAX_BLOCKS_HEADERS_IN_RANGE);
|
||||||
let rpc_config = Arc::new(RwLock::new(rpc_config));
|
let rpc_config = Arc::new(RwLock::new(rpc_config));
|
||||||
|
|
||||||
|
tracing::info!("Attempting to open cache at: {}", file_for_cache.display());
|
||||||
let cache = match ScanningCache::load(&file_for_cache) {
|
let cache = match ScanningCache::load(&file_for_cache) {
|
||||||
Ok(cache) => {
|
Ok(cache) => {
|
||||||
tracing::info!("Reloaded from cache, chain height: {}", cache.height);
|
tracing::info!("Reloaded from cache, chain height: {}", cache.height);
|
||||||
Arc::new(RwLock::new(cache))
|
Arc::new(RwLock::new(cache))
|
||||||
}
|
}
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
tracing::info!("Couldn't load from cache starting from scratch");
|
tracing::warn!("Couldn't load from cache starting from scratch");
|
||||||
let mut cache = ScanningCache::default();
|
let mut cache = ScanningCache::default();
|
||||||
let genesis = monero_consensus::genesis::generate_genesis_block(&network);
|
let genesis = monero_consensus::genesis::generate_genesis_block(&network);
|
||||||
|
|
||||||
|
|
|
@ -297,12 +297,10 @@ impl Service<BlockChainContextRequest> for BlockChainContextService {
|
||||||
next_difficulty: difficulty_cache.next_difficulty(¤t_hf),
|
next_difficulty: difficulty_cache.next_difficulty(¤t_hf),
|
||||||
cumulative_difficulty: difficulty_cache.cumulative_difficulty(),
|
cumulative_difficulty: difficulty_cache.cumulative_difficulty(),
|
||||||
effective_median_weight: weight_cache
|
effective_median_weight: weight_cache
|
||||||
.effective_median_block_weight(¤t_hf)
|
.effective_median_block_weight(¤t_hf),
|
||||||
.await,
|
median_long_term_weight: weight_cache.median_long_term_weight(),
|
||||||
median_long_term_weight: weight_cache.median_long_term_weight().await,
|
|
||||||
median_weight_for_block_reward: weight_cache
|
median_weight_for_block_reward: weight_cache
|
||||||
.median_for_block_reward(¤t_hf)
|
.median_for_block_reward(¤t_hf),
|
||||||
.await,
|
|
||||||
already_generated_coins: *already_generated_coins,
|
already_generated_coins: *already_generated_coins,
|
||||||
top_block_timestamp: difficulty_cache.top_block_timestamp(),
|
top_block_timestamp: difficulty_cache.top_block_timestamp(),
|
||||||
median_block_timestamp: difficulty_cache.median_timestamp(
|
median_block_timestamp: difficulty_cache.median_timestamp(
|
||||||
|
|
|
@ -77,6 +77,14 @@ impl BlockWeightsCacheConfig {
|
||||||
pub struct BlockWeightsCache {
|
pub struct BlockWeightsCache {
|
||||||
short_term_block_weights: VecDeque<usize>,
|
short_term_block_weights: VecDeque<usize>,
|
||||||
long_term_weights: VecDeque<usize>,
|
long_term_weights: VecDeque<usize>,
|
||||||
|
|
||||||
|
/// The short term block weights sorted so we don't have to sort them every time we need
|
||||||
|
/// the median.
|
||||||
|
cached_sorted_long_term_weights: Vec<usize>,
|
||||||
|
/// The long term block weights sorted so we don't have to sort them every time we need
|
||||||
|
/// the median.
|
||||||
|
cached_sorted_short_term_weights: Vec<usize>,
|
||||||
|
|
||||||
/// The height of the top block.
|
/// The height of the top block.
|
||||||
tip_height: u64,
|
tip_height: u64,
|
||||||
|
|
||||||
|
@ -93,25 +101,37 @@ impl BlockWeightsCache {
|
||||||
) -> Result<Self, ConsensusError> {
|
) -> Result<Self, ConsensusError> {
|
||||||
tracing::info!("Initializing weight cache this may take a while.");
|
tracing::info!("Initializing weight cache this may take a while.");
|
||||||
|
|
||||||
let long_term_weights: VecDeque<usize> = get_long_term_weight_in_range(
|
let long_term_weights = get_long_term_weight_in_range(
|
||||||
chain_height.saturating_sub(config.long_term_window)..chain_height,
|
chain_height.saturating_sub(config.long_term_window)..chain_height,
|
||||||
database.clone(),
|
database.clone(),
|
||||||
)
|
)
|
||||||
.await?
|
.await?;
|
||||||
.into();
|
|
||||||
|
|
||||||
let short_term_block_weights: VecDeque<usize> = get_blocks_weight_in_range(
|
let short_term_block_weights = get_blocks_weight_in_range(
|
||||||
chain_height.saturating_sub(config.short_term_window)..chain_height,
|
chain_height.saturating_sub(config.short_term_window)..chain_height,
|
||||||
database,
|
database,
|
||||||
)
|
)
|
||||||
.await?
|
.await?;
|
||||||
.into();
|
|
||||||
|
|
||||||
tracing::info!("Initialized block weight cache, chain-height: {:?}, long term weights length: {:?}, short term weights length: {:?}", chain_height, long_term_weights.len(), short_term_block_weights.len());
|
tracing::info!("Initialized block weight cache, chain-height: {:?}, long term weights length: {:?}, short term weights length: {:?}", chain_height, long_term_weights.len(), short_term_block_weights.len());
|
||||||
|
|
||||||
|
let mut cloned_short_term_weights = short_term_block_weights.clone();
|
||||||
|
let mut cloned_long_term_weights = long_term_weights.clone();
|
||||||
Ok(BlockWeightsCache {
|
Ok(BlockWeightsCache {
|
||||||
short_term_block_weights,
|
short_term_block_weights: short_term_block_weights.into(),
|
||||||
long_term_weights,
|
long_term_weights: long_term_weights.into(),
|
||||||
|
|
||||||
|
cached_sorted_long_term_weights: rayon_spawn_async(|| {
|
||||||
|
cloned_long_term_weights.par_sort_unstable();
|
||||||
|
cloned_long_term_weights
|
||||||
|
})
|
||||||
|
.await,
|
||||||
|
cached_sorted_short_term_weights: rayon_spawn_async(|| {
|
||||||
|
cloned_short_term_weights.par_sort_unstable();
|
||||||
|
cloned_short_term_weights
|
||||||
|
})
|
||||||
|
.await,
|
||||||
|
|
||||||
tip_height: chain_height - 1,
|
tip_height: chain_height - 1,
|
||||||
config,
|
config,
|
||||||
})
|
})
|
||||||
|
@ -132,59 +152,88 @@ impl BlockWeightsCache {
|
||||||
);
|
);
|
||||||
|
|
||||||
self.long_term_weights.push_back(long_term_weight);
|
self.long_term_weights.push_back(long_term_weight);
|
||||||
|
match self
|
||||||
|
.cached_sorted_long_term_weights
|
||||||
|
.binary_search(&long_term_weight)
|
||||||
|
{
|
||||||
|
Ok(idx) | Err(idx) => self
|
||||||
|
.cached_sorted_long_term_weights
|
||||||
|
.insert(idx, long_term_weight),
|
||||||
|
}
|
||||||
|
|
||||||
if u64::try_from(self.long_term_weights.len()).unwrap() > self.config.long_term_window {
|
if u64::try_from(self.long_term_weights.len()).unwrap() > self.config.long_term_window {
|
||||||
self.long_term_weights.pop_front();
|
let val = self
|
||||||
|
.long_term_weights
|
||||||
|
.pop_front()
|
||||||
|
.expect("long term window can't be negative");
|
||||||
|
|
||||||
|
match self.cached_sorted_long_term_weights.binary_search(&val) {
|
||||||
|
Ok(idx) | Err(idx) => self.cached_sorted_long_term_weights.remove(idx),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
self.short_term_block_weights.push_back(block_weight);
|
self.short_term_block_weights.push_back(block_weight);
|
||||||
|
match self
|
||||||
|
.cached_sorted_short_term_weights
|
||||||
|
.binary_search(&long_term_weight)
|
||||||
|
{
|
||||||
|
Ok(idx) | Err(idx) => self
|
||||||
|
.cached_sorted_short_term_weights
|
||||||
|
.insert(idx, long_term_weight),
|
||||||
|
}
|
||||||
|
|
||||||
if u64::try_from(self.short_term_block_weights.len()).unwrap()
|
if u64::try_from(self.short_term_block_weights.len()).unwrap()
|
||||||
> self.config.short_term_window
|
> self.config.short_term_window
|
||||||
{
|
{
|
||||||
self.short_term_block_weights.pop_front();
|
let val = self
|
||||||
|
.short_term_block_weights
|
||||||
|
.pop_front()
|
||||||
|
.expect("short term window can't be negative");
|
||||||
|
|
||||||
|
match self.cached_sorted_short_term_weights.binary_search(&val) {
|
||||||
|
Ok(idx) | Err(idx) => self.cached_sorted_short_term_weights.remove(idx),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
debug_assert_eq!(
|
||||||
|
self.cached_sorted_long_term_weights.len(),
|
||||||
|
self.long_term_weights.len()
|
||||||
|
);
|
||||||
|
debug_assert_eq!(
|
||||||
|
self.cached_sorted_short_term_weights.len(),
|
||||||
|
self.short_term_block_weights.len()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the median long term weight over the last [`LONG_TERM_WINDOW`] blocks, or custom amount of blocks in the config.
|
/// Returns the median long term weight over the last [`LONG_TERM_WINDOW`] blocks, or custom amount of blocks in the config.
|
||||||
pub async fn median_long_term_weight(&self) -> usize {
|
pub fn median_long_term_weight(&self) -> usize {
|
||||||
let mut sorted_long_term_weights: Vec<usize> = self.long_term_weights.clone().into();
|
median(&self.cached_sorted_long_term_weights)
|
||||||
|
|
||||||
// Move this out of the async runtime as this can take a bit.
|
|
||||||
let sorted_long_term_weights = rayon_spawn_async(|| {
|
|
||||||
sorted_long_term_weights.par_sort_unstable();
|
|
||||||
sorted_long_term_weights
|
|
||||||
})
|
|
||||||
.await;
|
|
||||||
|
|
||||||
median(&sorted_long_term_weights)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn median_short_term_weight(&self) -> usize {
|
pub fn median_short_term_weight(&self) -> usize {
|
||||||
let mut sorted_short_term_block_weights: Vec<usize> =
|
median(&self.cached_sorted_short_term_weights)
|
||||||
self.short_term_block_weights.clone().into();
|
|
||||||
sorted_short_term_block_weights.sort_unstable();
|
|
||||||
median(&sorted_short_term_block_weights)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the effective median weight, used for block reward calculations and to calculate
|
/// Returns the effective median weight, used for block reward calculations and to calculate
|
||||||
/// the block weight limit.
|
/// the block weight limit.
|
||||||
///
|
///
|
||||||
/// See: https://cuprate.github.io/monero-book/consensus_rules/blocks/weight_limit.html#calculating-effective-median-weight
|
/// See: https://cuprate.github.io/monero-book/consensus_rules/blocks/weight_limit.html#calculating-effective-median-weight
|
||||||
pub async fn effective_median_block_weight(&self, hf: &HardFork) -> usize {
|
pub fn effective_median_block_weight(&self, hf: &HardFork) -> usize {
|
||||||
calculate_effective_median_block_weight(
|
calculate_effective_median_block_weight(
|
||||||
hf,
|
hf,
|
||||||
self.median_short_term_weight(),
|
self.median_short_term_weight(),
|
||||||
self.median_long_term_weight().await,
|
self.median_long_term_weight(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the median weight used to calculate block reward punishment.
|
/// Returns the median weight used to calculate block reward punishment.
|
||||||
///
|
///
|
||||||
/// https://cuprate.github.io/monero-book/consensus_rules/blocks/reward.html#calculating-block-reward
|
/// https://cuprate.github.io/monero-book/consensus_rules/blocks/reward.html#calculating-block-reward
|
||||||
pub async fn median_for_block_reward(&self, hf: &HardFork) -> usize {
|
pub fn median_for_block_reward(&self, hf: &HardFork) -> usize {
|
||||||
if hf.in_range(&HardFork::V1, &HardFork::V12) {
|
if hf.in_range(&HardFork::V1, &HardFork::V12) {
|
||||||
self.median_short_term_weight()
|
self.median_short_term_weight()
|
||||||
} else {
|
} else {
|
||||||
self.effective_median_block_weight(hf).await
|
self.effective_median_block_weight(hf)
|
||||||
}
|
}
|
||||||
.max(penalty_free_zone(hf))
|
.max(penalty_free_zone(hf))
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue