Apply min_num_nonces and min_solution_ratio to filter qualifiers.
Some checks are pending
Test Workspace / Test Workspace (push) Waiting to run

This commit is contained in:
FiveMovesAhead 2025-03-24 14:25:52 +08:00
parent cc568d9523
commit 43ef0f1856
3 changed files with 110 additions and 101 deletions

View File

@ -40,15 +40,6 @@ pub async fn submit_precommit<T: Context>(
return Err(anyhow!("Invalid challenge '{}'", settings.challenge_id));
}
// verify min nonces
let min_nonces = config.benchmarks.min_nonces[&settings.challenge_id];
if num_nonces < min_nonces {
return Err(anyhow!(
"Invalid num_nonces. Must be at least {}",
min_nonces
));
}
// verify algorithm is active
if !ctx
.get_algorithm_state(&settings.algorithm_id)

View File

@ -128,111 +128,129 @@ pub(crate) async fn update(cache: &mut AddBlockCache) {
frontier_indexes.insert(point, frontier_index);
}
}
solutions.sort_by(|(a_settings, _, _), (b_settings, _, _)| {
let a_index = frontier_indexes[&a_settings.difficulty];
let b_index = frontier_indexes[&b_settings.difficulty];
a_index.cmp(&b_index)
});
let mut solutions_by_frontier_idx =
HashMap::<usize, Vec<(&BenchmarkSettings, &u32, &u32)>>::new();
for &x in solutions.iter() {
solutions_by_frontier_idx
.entry(frontier_indexes[&x.0.difficulty])
.or_default()
.push(x);
}
let mut max_qualifiers_by_player = max_qualifiers_by_player.clone();
let mut curr_frontier_index = 0;
let challenge_data = active_challenges_block_data.get_mut(challenge_id).unwrap();
let prev_solution_ratio = active_challenges_prev_block_data
.get(challenge_id)
.map(|x| x.average_solution_ratio)
.unwrap_or_default();
let min_solution_ratio = prev_solution_ratio * config.opow.min_solution_ratio_factor;
for (settings, &num_solutions, &num_nonces) in solutions.iter() {
let BenchmarkSettings {
player_id,
algorithm_id,
challenge_id,
difficulty,
..
} = settings;
let min_num_nonces = config.opow.min_num_nonces;
let mut player_algorithm_solutions = HashMap::<String, HashMap<String, u32>>::new();
let mut player_solutions = HashMap::<String, u32>::new();
let mut player_nonces = HashMap::<String, u32>::new();
if curr_frontier_index != frontier_indexes[difficulty]
&& challenge_data.num_qualifiers > config.opow.total_qualifiers_threshold
for frontier_idx in 0..solutions_by_frontier_idx.len() {
for (settings, &num_solutions, &num_nonces) in
solutions_by_frontier_idx[&frontier_idx].iter()
{
let BenchmarkSettings {
player_id,
algorithm_id,
challenge_id,
difficulty,
..
} = settings;
let difficulty_parameters = &config.challenges.difficulty_parameters[challenge_id];
let min_difficulty = difficulty_parameters.min_difficulty();
let max_difficulty = difficulty_parameters.max_difficulty();
if (0..difficulty.len())
.into_iter()
.any(|i| difficulty[i] < min_difficulty[i] || difficulty[i] > max_difficulty[i])
{
continue;
}
*player_algorithm_solutions
.entry(player_id.clone())
.or_default()
.entry(algorithm_id.clone())
.or_default() += num_solutions;
*player_solutions.entry(player_id.clone()).or_default() += num_solutions;
*player_nonces.entry(player_id.clone()).or_default() += num_nonces;
challenge_data
.qualifier_difficulties
.insert(difficulty.clone());
}
// check if we have enough qualifiers
let player_solution_ratio: HashMap<String, f64> = player_solutions
.keys()
.map(|player_id| {
(
player_id.clone(),
player_solutions[player_id] as f64 / player_nonces[player_id] as f64,
)
})
.collect();
let player_qualifiers: HashMap<String, u32> = player_solution_ratio
.keys()
.map(|player_id| {
(
player_id.clone(),
if player_nonces[player_id] >= min_num_nonces
&& player_solution_ratio[player_id] >= min_solution_ratio
{
max_qualifiers_by_player[player_id].min(player_solutions[player_id])
} else {
0
},
)
})
.collect();
let num_qualifiers = player_qualifiers.values().sum::<u32>();
if num_qualifiers >= config.opow.total_qualifiers_threshold
|| frontier_idx == solutions_by_frontier_idx.len() - 1
{
let mut sum_weighted_solution_ratio = 0.0;
for player_id in player_qualifiers.keys() {
let opow_data = active_opow_block_data.get_mut(player_id).unwrap();
opow_data
.num_qualifiers_by_challenge
.insert(challenge_id.clone(), player_qualifiers[player_id]);
opow_data
.solution_ratio_by_challenge
.insert(challenge_id.clone(), player_solution_ratio[player_id]);
sum_weighted_solution_ratio +=
player_solution_ratio[player_id] * player_qualifiers[player_id] as f64;
if player_qualifiers[player_id] > 0 {
for algorithm_id in player_algorithm_solutions[player_id].keys() {
let algorithm_data =
active_algorithms_block_data.get_mut(algorithm_id).unwrap();
algorithm_data.num_qualifiers_by_player.insert(
player_id.clone(),
(player_qualifiers[player_id] as f64
* player_algorithm_solutions[player_id][algorithm_id] as f64
/ player_solutions[player_id] as f64)
.ceil() as u32,
);
}
}
}
challenge_data.num_qualifiers = num_qualifiers;
challenge_data.average_solution_ratio = if num_qualifiers == 0 {
0.0
} else {
sum_weighted_solution_ratio / num_qualifiers as f64
};
break;
}
let difficulty_parameters = &config.challenges.difficulty_parameters[challenge_id];
let min_difficulty = difficulty_parameters.min_difficulty();
let max_difficulty = difficulty_parameters.max_difficulty();
if (0..difficulty.len())
.into_iter()
.any(|i| difficulty[i] < min_difficulty[i] || difficulty[i] > max_difficulty[i])
{
continue;
}
curr_frontier_index = frontier_indexes[difficulty];
let player_data = active_opow_block_data.get_mut(player_id).unwrap();
let algorithm_data = active_algorithms_block_data.get_mut(algorithm_id).unwrap();
let max_qualifiers = max_qualifiers_by_player.get(player_id).unwrap().clone();
let solution_ratio = num_solutions as f64 / num_nonces as f64;
let num_qualifiers = if solution_ratio >= min_solution_ratio {
num_solutions.min(max_qualifiers)
} else {
0
};
max_qualifiers_by_player.insert(player_id.clone(), max_qualifiers - num_qualifiers);
if num_qualifiers > 0 {
*player_data
.num_qualifiers_by_challenge
.entry(challenge_id.clone())
.or_default() += num_qualifiers;
*algorithm_data
.num_qualifiers_by_player
.entry(player_id.clone())
.or_default() += num_qualifiers;
challenge_data.num_qualifiers += num_qualifiers;
}
challenge_data
.qualifier_difficulties
.insert(difficulty.clone());
}
}
// update reliability
for challenge_id in active_challenge_ids.iter() {
if !solutions_by_challenge.contains_key(challenge_id) {
continue;
}
let solutions = solutions_by_challenge.get(challenge_id).unwrap();
let challenge_data = active_challenges_block_data.get_mut(challenge_id).unwrap();
let mut total_solutions = HashMap::<String, u32>::new();
let mut total_nonces = HashMap::<String, u32>::new();
for (settings, num_solutions, num_nonces) in solutions.iter() {
if !challenge_data
.qualifier_difficulties
.contains(&settings.difficulty)
{
continue;
}
*total_solutions
.entry(settings.player_id.clone())
.or_default() += *num_solutions;
*total_nonces.entry(settings.player_id.clone()).or_default() += *num_nonces;
}
let mut sum_weighted_solution_ratio = 0.0;
for player_id in total_solutions.keys() {
let solution_ratio = total_solutions[player_id] as f64 / total_nonces[player_id] as f64;
let opow_data = active_opow_block_data.get_mut(player_id).unwrap();
if let Some(&num_qualifiers) = opow_data.num_qualifiers_by_challenge.get(challenge_id) {
sum_weighted_solution_ratio += solution_ratio * num_qualifiers as f64;
}
opow_data
.solution_ratio_by_challenge
.insert(challenge_id.clone(), solution_ratio);
}
challenge_data.average_solution_ratio =
sum_weighted_solution_ratio / challenge_data.num_qualifiers as f64;
}
// update frontiers
for challenge_id in active_challenge_ids.iter() {
let challenge_data = active_challenges_block_data.get_mut(challenge_id).unwrap();

View File

@ -68,7 +68,6 @@ serializable_struct_with_getters! {
min_per_nonce_fee: PreciseNumber,
min_base_fee: PreciseNumber,
runtime_configs: HashMap<AlgorithmType, RuntimeConfig>,
min_nonces: HashMap<String, u32>,
}
}
serializable_struct_with_getters! {
@ -114,6 +113,7 @@ serializable_struct_with_getters! {
max_coinbase_outputs: usize,
coinbase_update_period: u32,
min_solution_ratio_factor: f64,
min_num_nonces: u32,
}
}
serializable_struct_with_getters! {