Skip to content

Commit bd03469

Browse files
tmpolaczykmariocao
andcommitted
feat(validations): set a maximum eligibility for data requests
Co-authored-by: Mario Cao <[email protected]>
1 parent 7460dd3 commit bd03469

File tree

4 files changed

+76
-40
lines changed

4 files changed

+76
-40
lines changed

data_structures/src/mainnet_validations.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ const SECOND_EMERGENCY_COMMITTEE: [&str; 6] = [
2525
pub const FIRST_HARD_FORK: Epoch = 192000;
2626
/// 28 April 2021 @ 9:00:00 UTC
2727
pub const SECOND_HARD_FORK: Epoch = 376320;
28+
/// 4 June 2021 @ 9:00:00 UTC
29+
pub const THIRD_HARD_FORK: Epoch = 447360;
2830

2931
/// Return a hard-coded signing committee if the provided epoch belongs to an emergency period.
3032
/// 750 and 1344: Between those indices, a special committee of 7 nodes was set.
@@ -64,6 +66,11 @@ pub fn after_second_hard_fork(epoch: Epoch, environment: Environment) -> bool {
6466
epoch >= SECOND_HARD_FORK && Environment::Mainnet == environment
6567
}
6668

69+
/// Returns a boolean indicating whether the epoch provided is after the third hard fork date
70+
pub fn after_third_hard_fork(epoch: Epoch, environment: Environment) -> bool {
71+
epoch >= THIRD_HARD_FORK && Environment::Mainnet == environment
72+
}
73+
6774
#[cfg(test)]
6875
mod tests {
6976
use super::*;

node/src/actors/chain_manager/mining.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -322,8 +322,15 @@ impl ChainManager {
322322
..vrf_input
323323
};
324324

325-
let (target_hash, probability) =
326-
calculate_reppoe_threshold(rep_eng, &own_pkh, num_witnesses + num_backup_witnesses);
325+
// TODO: pass difficulty as an argument to this function (from consensus constants)
326+
let minimum_reppoe_difficulty = 2000;
327+
let (target_hash, probability) = calculate_reppoe_threshold(
328+
rep_eng,
329+
&own_pkh,
330+
num_witnesses + num_backup_witnesses,
331+
current_epoch,
332+
minimum_reppoe_difficulty,
333+
);
327334

328335
// Grab a reference to `current_retrieval_count`
329336
let cloned_retrieval_count = Arc::clone(&current_retrieval_count);

validations/benches/reppoe.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,15 +73,15 @@ fn be<I>(
7373
}
7474
// Initialize cache
7575
rep_eng.total_active_reputation();
76-
validations::calculate_reppoe_threshold(&rep_eng, &my_pkh, num_witnesses);
76+
validations::calculate_reppoe_threshold(&rep_eng, &my_pkh, num_witnesses, 0, 2000);
7777
b.iter(|| {
7878
if invalidate_sorted_cache {
7979
rep_eng.invalidate_reputation_threshold_cache()
8080
}
8181
if invalidate_threshold_cache {
8282
rep_eng.clear_threshold_cache();
8383
}
84-
validations::calculate_reppoe_threshold(&rep_eng, &my_pkh, num_witnesses)
84+
validations::calculate_reppoe_threshold(&rep_eng, &my_pkh, num_witnesses, 0, 2000)
8585
})
8686
}
8787

validations/src/validations.rs

Lines changed: 58 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use witnet_data_structures::{
2626
},
2727
error::{BlockError, DataRequestError, TransactionError},
2828
get_environment,
29-
mainnet_validations::{after_first_hard_fork, after_second_hard_fork},
29+
mainnet_validations::{after_first_hard_fork, after_second_hard_fork, after_third_hard_fork},
3030
radon_error::RadonError,
3131
radon_report::{RadonReport, ReportContext, Stage, TallyMetaData},
3232
transaction::{
@@ -916,7 +916,15 @@ pub fn validate_commit_transaction(
916916
let pkh = proof_pkh;
917917
let backup_witnesses = dr_state.backup_witnesses();
918918
let num_witnesses = dr_output.witnesses + backup_witnesses;
919-
let (target_hash, _) = calculate_reppoe_threshold(rep_eng, &pkh, num_witnesses);
919+
// TODO: pass difficulty as an argument to this function (from consensus constants)
920+
let minimum_reppoe_difficulty = 2000;
921+
let (target_hash, _) = calculate_reppoe_threshold(
922+
rep_eng,
923+
&pkh,
924+
num_witnesses,
925+
epoch,
926+
minimum_reppoe_difficulty,
927+
);
920928
add_dr_vrf_signature_to_verify(
921929
signatures_to_verify,
922930
&co_tx.body.proof,
@@ -1548,6 +1556,7 @@ struct WitnessesCount {
15481556
current: u32,
15491557
target: u32,
15501558
}
1559+
15511560
type WitnessesCounter<S> = HashMap<Hash, WitnessesCount, S>;
15521561

15531562
// Add 1 in the number assigned to a OutputPointer
@@ -2091,20 +2100,31 @@ pub fn calculate_reppoe_threshold(
20912100
rep_eng: &ReputationEngine,
20922101
pkh: &PublicKeyHash,
20932102
num_witnesses: u16,
2103+
block_epoch: u32,
2104+
minimum_difficulty: u32,
20942105
) -> (Hash, f64) {
2095-
let total_active_rep = rep_eng.total_active_reputation();
2096-
20972106
// Add 1 to reputation because otherwise a node with 0 reputation would
20982107
// never be eligible for a data request
2099-
let my_reputation = u64::from(rep_eng.get_eligibility(pkh)) + 1;
2108+
let my_eligibility = u64::from(rep_eng.get_eligibility(pkh)) + 1;
21002109
let factor = u64::from(rep_eng.threshold_factor(num_witnesses));
21012110

21022111
let max = u64::max_value();
2103-
// Check for overflow: when the probability is more than 100%, cap it to 100%
2104-
let target = if my_reputation.saturating_mul(factor) >= total_active_rep {
2105-
max
2112+
// Compute target eligibility and hard-cap it if required
2113+
let target = if after_third_hard_fork(block_epoch, get_environment()) {
2114+
// TODO: Review if next line is required (check if total active reputation could be zero)
2115+
let total_active_rep = std::cmp::max(rep_eng.total_active_reputation(), 1);
2116+
// If eligibility is more than 100%, cap it to (max/minimum_difficulty*factor)%
2117+
std::cmp::min(
2118+
max / u64::from(minimum_difficulty),
2119+
(max / total_active_rep).saturating_mul(my_eligibility),
2120+
)
2121+
.saturating_mul(factor)
21062122
} else {
2107-
(max / total_active_rep) * my_reputation.saturating_mul(factor)
2123+
// Check for overflow: when the probability is more than 100%, cap it to 100%
2124+
let total_active_rep = rep_eng.total_active_reputation();
2125+
(max / total_active_rep)
2126+
.saturating_mul(my_eligibility)
2127+
.saturating_mul(factor)
21082128
};
21092129
let target = u32::try_from(target >> 32).unwrap();
21102130

@@ -2222,7 +2242,8 @@ pub fn validate_merkle_tree(block: &Block) -> bool {
22222242

22232243
/// 1 nanowit is the minimal unit of value
22242244
/// 1 wit = 10^9 nanowits
2225-
pub const NANOWITS_PER_WIT: u64 = 1_000_000_000; // 10 ^ WIT_DECIMAL_PLACES
2245+
pub const NANOWITS_PER_WIT: u64 = 1_000_000_000;
2246+
// 10 ^ WIT_DECIMAL_PLACES
22262247
/// Number of decimal places used in the string representation of wit value.
22272248
pub const WIT_DECIMAL_PLACES: u8 = 9;
22282249

@@ -2482,7 +2503,7 @@ mod tests {
24822503
rep_2,
24832504
vrf_j,
24842505
act_j,
2485-
&vrf_sections
2506+
&vrf_sections,
24862507
),
24872508
Ordering::Less
24882509
);
@@ -2496,7 +2517,7 @@ mod tests {
24962517
rep_1,
24972518
vrf_j,
24982519
act_j,
2499-
&vrf_sections
2520+
&vrf_sections,
25002521
),
25012522
Ordering::Greater
25022523
);
@@ -2522,7 +2543,7 @@ mod tests {
25222543
rep_1,
25232544
vrf_j,
25242545
false,
2525-
&vrf_sections
2546+
&vrf_sections,
25262547
),
25272548
Ordering::Greater
25282549
);
@@ -2536,7 +2557,7 @@ mod tests {
25362557
rep_2,
25372558
vrf_j,
25382559
true,
2539-
&vrf_sections
2560+
&vrf_sections,
25402561
),
25412562
Ordering::Less
25422563
);
@@ -2558,7 +2579,7 @@ mod tests {
25582579
rep_1,
25592580
vrf_2,
25602581
true,
2561-
&vrf_sections
2582+
&vrf_sections,
25622583
),
25632584
Ordering::Greater
25642585
);
@@ -2572,7 +2593,7 @@ mod tests {
25722593
rep_1,
25732594
vrf_1,
25742595
true,
2575-
&vrf_sections
2596+
&vrf_sections,
25762597
),
25772598
Ordering::Less
25782599
);
@@ -2590,7 +2611,7 @@ mod tests {
25902611
rep_1,
25912612
vrf_1,
25922613
true,
2593-
&vrf_sections
2614+
&vrf_sections,
25942615
),
25952616
Ordering::Greater
25962617
);
@@ -2604,7 +2625,7 @@ mod tests {
26042625
rep_1,
26052626
vrf_1,
26062627
true,
2607-
&vrf_sections
2628+
&vrf_sections,
26082629
),
26092630
Ordering::Less
26102631
);
@@ -2620,7 +2641,7 @@ mod tests {
26202641
rep_1,
26212642
vrf_1,
26222643
true,
2623-
&vrf_sections
2644+
&vrf_sections,
26242645
),
26252646
Ordering::Equal
26262647
);
@@ -2656,7 +2677,7 @@ mod tests {
26562677
rep_j,
26572678
vrf_2,
26582679
act_j,
2659-
&vrf_sections
2680+
&vrf_sections,
26602681
),
26612682
Ordering::Greater
26622683
);
@@ -2670,7 +2691,7 @@ mod tests {
26702691
rep_j,
26712692
vrf_1,
26722693
act_j,
2673-
&vrf_sections
2694+
&vrf_sections,
26742695
),
26752696
Ordering::Less
26762697
);
@@ -2704,7 +2725,7 @@ mod tests {
27042725
rep_2,
27052726
vrf_2,
27062727
true,
2707-
&vrf_sections
2728+
&vrf_sections,
27082729
),
27092730
Ordering::Greater
27102731
);
@@ -2719,7 +2740,7 @@ mod tests {
27192740
rep_2,
27202741
vrf_1,
27212742
true,
2722-
&vrf_sections
2743+
&vrf_sections,
27232744
),
27242745
Ordering::Less
27252746
);
@@ -2950,7 +2971,7 @@ mod tests {
29502971
rep_engine.ars_mut().push_activity(vec![id1]);
29512972

29522973
// 100% when we have all the reputation
2953-
let (t00, p00) = calculate_reppoe_threshold(&rep_engine, &id1, 1);
2974+
let (t00, p00) = calculate_reppoe_threshold(&rep_engine, &id1, 1, 0, 2000);
29542975
assert_eq!(t00, Hash::with_first_u32(0xFFFF_FFFF));
29552976
assert_eq!((p00 * 100_f64).round() as i128, 100);
29562977

@@ -2962,7 +2983,7 @@ mod tests {
29622983
rep_engine.ars_mut().push_activity(vec![id2]);
29632984

29642985
// 50% when there are 2 nodes with 50% of the reputation each
2965-
let (t01, p01) = calculate_reppoe_threshold(&rep_engine, &id1, 1);
2986+
let (t01, p01) = calculate_reppoe_threshold(&rep_engine, &id1, 1, 0, 2000);
29662987
// Since the calculate_reppoe function first divides and later
29672988
// multiplies, we get a rounding error here
29682989
assert_eq!(t01, Hash::with_first_u32(0x7FFF_FFFF));
@@ -3003,7 +3024,8 @@ mod tests {
30033024
let mut v = vec![];
30043025
for id in ids.iter() {
30053026
v.push(
3006-
(calculate_reppoe_threshold(&rep_engine, id, thres).1 * 100_f64).round() as u32,
3027+
(calculate_reppoe_threshold(&rep_engine, id, thres, 0, 2000).1 * 100_f64)
3028+
.round() as u32,
30073029
);
30083030
}
30093031
v
@@ -3034,16 +3056,16 @@ mod tests {
30343056
let id0 = PublicKeyHash::from_bytes(&[0; 20]).unwrap();
30353057

30363058
// 100% when the total reputation is 0
3037-
let (t00, p00) = calculate_reppoe_threshold(&rep_engine, &id0, 1);
3038-
assert_eq!(t00, Hash::with_first_u32(0xFFFF_FFFF));
3059+
let (t00, p00) = calculate_reppoe_threshold(&rep_engine, &id0, 1, 0, 2000);
30393060
assert_eq!((p00 * 100_f64).round() as i128, 100);
3040-
let (t01, p01) = calculate_reppoe_threshold(&rep_engine, &id0, 100);
3061+
assert_eq!(t00, Hash::with_first_u32(0xFFFF_FFFF));
3062+
let (t01, p01) = calculate_reppoe_threshold(&rep_engine, &id0, 100, 0, 2000);
30413063
assert_eq!(t01, Hash::with_first_u32(0xFFFF_FFFF));
30423064
assert_eq!((p01 * 100_f64).round() as i128, 100);
30433065

30443066
let id1 = PublicKeyHash::from_bytes(&[1; 20]).unwrap();
30453067
rep_engine.ars_mut().push_activity(vec![id1]);
3046-
let (t02, p02) = calculate_reppoe_threshold(&rep_engine, &id0, 1);
3068+
let (t02, p02) = calculate_reppoe_threshold(&rep_engine, &id0, 1, 0, 2000);
30473069
assert_eq!(t02, Hash::with_first_u32(0xFFFF_FFFF));
30483070
assert_eq!((p02 * 100_f64).round() as i128, 100);
30493071

@@ -3052,14 +3074,14 @@ mod tests {
30523074
.trs_mut()
30533075
.gain(Alpha(10), vec![(id1, Reputation(1))])
30543076
.unwrap();
3055-
let (t03, p03) = calculate_reppoe_threshold(&rep_engine, &id0, 1);
3077+
let (t03, p03) = calculate_reppoe_threshold(&rep_engine, &id0, 1, 0, 2000);
30563078
assert_eq!(t03, Hash::with_first_u32(0x7FFF_FFFF));
30573079
assert_eq!((p03 * 100_f64).round() as i128, 50);
30583080

30593081
// 33% when the total reputation is 1 but there are 2 active identities
30603082
let id2 = PublicKeyHash::from_bytes(&[2; 20]).unwrap();
30613083
rep_engine.ars_mut().push_activity(vec![id2]);
3062-
let (t04, p04) = calculate_reppoe_threshold(&rep_engine, &id0, 1);
3084+
let (t04, p04) = calculate_reppoe_threshold(&rep_engine, &id0, 1, 0, 2000);
30633085
assert_eq!(t04, Hash::with_first_u32(0x5555_5555));
30643086
assert_eq!((p04 * 100_f64).round() as i128, 33);
30653087

@@ -3073,7 +3095,7 @@ mod tests {
30733095
.trs_mut()
30743096
.gain(Alpha(10), vec![(id1, Reputation(99))])
30753097
.unwrap();
3076-
let (t05, p05) = calculate_reppoe_threshold(&rep_engine, &id0, 1);
3098+
let (t05, p05) = calculate_reppoe_threshold(&rep_engine, &id0, 1, 0, 2000);
30773099
assert_eq!(t05, Hash::with_first_u32(0x0253_C825));
30783100
assert_eq!((p05 * 100_f64).round() as i128, 1);
30793101
}
@@ -3094,7 +3116,7 @@ mod tests {
30943116
.unwrap();
30953117

30963118
// Test big values that result in < 100%
3097-
let (t01, p01) = calculate_reppoe_threshold(&rep_engine, &id0, 1);
3119+
let (t01, p01) = calculate_reppoe_threshold(&rep_engine, &id0, 1, 0, 2000);
30983120
assert_eq!(t01, Hash::with_first_u32(0xFFFF_FFFE));
30993121
assert_eq!((p01 * 100_f64).round() as i128, 100);
31003122
}
@@ -3388,7 +3410,7 @@ mod tests {
33883410
out,
33893411
RadError::InsufficientConsensus {
33903412
achieved: 0.5,
3391-
required: 0.51
3413+
required: 0.51,
33923414
}
33933415
);
33943416
}
@@ -3415,7 +3437,7 @@ mod tests {
34153437
out,
34163438
RadError::InsufficientConsensus {
34173439
achieved: 0.5,
3418-
required: 0.51
3440+
required: 0.51,
34193441
}
34203442
);
34213443
}

0 commit comments

Comments
 (0)