Skip to content

Commit 65a45bc

Browse files
authored
Add global blacklist to validator-cache (#1168)
1 parent 5932974 commit 65a45bc

File tree

8 files changed

+159
-21
lines changed

8 files changed

+159
-21
lines changed

validator-api/src/config/mod.rs

+9
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ const DEFAULT_PER_NODE_TEST_PACKETS: usize = 3;
3434

3535
const DEFAULT_CACHE_INTERVAL: Duration = Duration::from_secs(30);
3636
const DEFAULT_MONITOR_THRESHOLD: u8 = 60;
37+
const DEFAULT_MIN_RELIABILITY: u8 = 50;
3738

3839
#[derive(Debug, Default, Deserialize, PartialEq, Serialize)]
3940
pub struct Config {
@@ -107,6 +108,9 @@ impl Default for Base {
107108
#[derive(Debug, Deserialize, PartialEq, Serialize)]
108109
#[serde(default)]
109110
pub struct NetworkMonitor {
111+
// Mixnodes and gateways with relialability lower the this get blacklisted by network monitor, get no traffic and cannot be selected into a rewarded set.
112+
min_reliability: u8,
113+
110114
/// Specifies whether network monitoring service is enabled in this process.
111115
enabled: bool,
112116

@@ -188,6 +192,7 @@ impl NetworkMonitor {
188192
impl Default for NetworkMonitor {
189193
fn default() -> Self {
190194
NetworkMonitor {
195+
min_reliability: DEFAULT_MIN_RELIABILITY,
191196
enabled: false,
192197
testnet_mode: false,
193198
all_validator_apis: default_api_endpoints(),
@@ -418,6 +423,10 @@ impl Config {
418423
self.network_monitor.minimum_test_routes
419424
}
420425

426+
pub fn get_min_reliability(&self) -> u8 {
427+
self.network_monitor.min_reliability
428+
}
429+
421430
pub fn get_route_test_packets(&self) -> usize {
422431
self.network_monitor.route_test_packets
423432
}

validator-api/src/config/template.rs

+3
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ mixnet_contract_address = '{{ base.mixnet_contract_address }}'
2020
2121
[network_monitor]
2222
23+
# Mixnodes and gateways with relialability lower the this get blacklisted by network monitor, get no traffic and cannot be selected into a rewarded set.
24+
min_reliability = {{ network_monitor.min_reliability }}
25+
2326
# Specifies whether network monitoring service is enabled in this process.
2427
enabled = {{ network_monitor.enabled }}
2528

validator-api/src/contract_cache/mod.rs

+82-4
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use mixnet_contract_common::{
1313
use rocket::fairing::AdHoc;
1414
use serde::Serialize;
1515
use std::collections::HashMap;
16+
use std::collections::HashSet;
1617
use std::sync::atomic::{AtomicBool, Ordering};
1718
use std::sync::Arc;
1819
use std::time::Duration;
@@ -40,6 +41,9 @@ struct ValidatorCacheInner {
4041
mixnodes: Cache<Vec<MixNodeBond>>,
4142
gateways: Cache<Vec<GatewayBond>>,
4243

44+
mixnodes_blacklist: Cache<HashSet<IdentityKey>>,
45+
gateways_blacklist: Cache<HashSet<IdentityKey>>,
46+
4347
rewarded_set: Cache<Vec<MixNodeBond>>,
4448
active_set: Cache<Vec<MixNodeBond>>,
4549

@@ -203,6 +207,8 @@ impl ValidatorCache {
203207
routes::get_gateways,
204208
routes::get_active_set,
205209
routes::get_rewarded_set,
210+
routes::get_blacklisted_mixnodes,
211+
routes::get_blacklisted_gateways,
206212
],
207213
)
208214
})
@@ -225,12 +231,82 @@ impl ValidatorCache {
225231
inner.current_reward_params.update(epoch_rewarding_params);
226232
}
227233

228-
pub async fn mixnodes(&self) -> Cache<Vec<MixNodeBond>> {
229-
self.inner.read().await.mixnodes.clone()
234+
pub async fn mixnodes_blacklist(&self) -> Cache<HashSet<IdentityKey>> {
235+
self.inner.read().await.mixnodes_blacklist.clone()
236+
}
237+
238+
pub async fn gateways_blacklist(&self) -> Cache<HashSet<IdentityKey>> {
239+
self.inner.read().await.gateways_blacklist.clone()
240+
}
241+
242+
pub async fn insert_mixnodes_blacklist(&mut self, mix_identity: IdentityKey) {
243+
self.inner
244+
.write()
245+
.await
246+
.mixnodes_blacklist
247+
.value
248+
.insert(mix_identity);
249+
}
250+
251+
pub async fn remove_mixnodes_blacklist(&mut self, mix_identity: &str) {
252+
self.inner
253+
.write()
254+
.await
255+
.mixnodes_blacklist
256+
.value
257+
.remove(mix_identity);
258+
}
259+
260+
pub async fn insert_gateways_blacklist(&mut self, gateway_identity: IdentityKey) {
261+
self.inner
262+
.write()
263+
.await
264+
.gateways_blacklist
265+
.value
266+
.insert(gateway_identity);
267+
}
268+
269+
pub async fn remove_gateways_blacklist(&mut self, gateway_identity: &str) {
270+
self.inner
271+
.write()
272+
.await
273+
.gateways_blacklist
274+
.value
275+
.remove(gateway_identity);
276+
}
277+
278+
pub async fn mixnodes(&self) -> Vec<MixNodeBond> {
279+
let blacklist = self.mixnodes_blacklist().await.value;
280+
self.inner
281+
.read()
282+
.await
283+
.mixnodes
284+
.value
285+
.iter()
286+
.filter(|mix| !blacklist.contains(mix.identity()))
287+
.cloned()
288+
.collect()
289+
}
290+
291+
pub async fn mixnodes_all(&self) -> Vec<MixNodeBond> {
292+
self.inner.read().await.mixnodes.value.clone()
293+
}
294+
295+
pub async fn gateways(&self) -> Vec<GatewayBond> {
296+
let blacklist = self.gateways_blacklist().await.value;
297+
self.inner
298+
.read()
299+
.await
300+
.gateways
301+
.value
302+
.iter()
303+
.filter(|gateway| !blacklist.contains(gateway.identity()))
304+
.cloned()
305+
.collect()
230306
}
231307

232-
pub async fn gateways(&self) -> Cache<Vec<GatewayBond>> {
233-
self.inner.read().await.gateways.clone()
308+
pub async fn gateways_all(&self) -> Vec<GatewayBond> {
309+
self.inner.read().await.gateways.value.clone()
234310
}
235311

236312
pub async fn rewarded_set(&self) -> Cache<Vec<MixNodeBond>> {
@@ -312,6 +388,8 @@ impl ValidatorCacheInner {
312388
rewarded_set: Cache::default(),
313389
active_set: Cache::default(),
314390
current_reward_params: Cache::new(EpochRewardParams::new_empty()),
391+
mixnodes_blacklist: Cache::default(),
392+
gateways_blacklist: Cache::default(),
315393
// setting it to a dummy value on creation is fine, as nothing will be able to ready from it
316394
// since 'initialised' flag won't be set
317395
current_epoch: Cache::new(None),

validator-api/src/contract_cache/routes.rs

+17-2
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,16 @@ use crate::contract_cache::ValidatorCache;
55
use mixnet_contract_common::{GatewayBond, MixNodeBond};
66
use rocket::serde::json::Json;
77
use rocket::State;
8+
use std::collections::HashSet;
89

910
#[get("/mixnodes")]
1011
pub(crate) async fn get_mixnodes(cache: &State<ValidatorCache>) -> Json<Vec<MixNodeBond>> {
11-
Json(cache.mixnodes().await.value)
12+
Json(cache.mixnodes().await)
1213
}
1314

1415
#[get("/gateways")]
1516
pub(crate) async fn get_gateways(cache: &State<ValidatorCache>) -> Json<Vec<GatewayBond>> {
16-
Json(cache.gateways().await.value)
17+
Json(cache.gateways().await)
1718
}
1819

1920
#[get("/mixnodes/rewarded")]
@@ -25,3 +26,17 @@ pub(crate) async fn get_rewarded_set(cache: &State<ValidatorCache>) -> Json<Vec<
2526
pub(crate) async fn get_active_set(cache: &State<ValidatorCache>) -> Json<Vec<MixNodeBond>> {
2627
Json(cache.active_set().await.value)
2728
}
29+
30+
#[get("/mixnodes/blacklisted")]
31+
pub(crate) async fn get_blacklisted_mixnodes(
32+
cache: &State<ValidatorCache>,
33+
) -> Json<HashSet<String>> {
34+
Json(cache.mixnodes_blacklist().await.value)
35+
}
36+
37+
#[get("/gateways/blacklisted")]
38+
pub(crate) async fn get_blacklisted_gateways(
39+
cache: &State<ValidatorCache>,
40+
) -> Json<HashSet<String>> {
41+
Json(cache.gateways_blacklist().await.value)
42+
}

validator-api/src/network_monitor/monitor/mod.rs

+32-1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ pub(super) struct Monitor {
4242
/// The minimum number of test routes that need to be constructed (and working) in order for
4343
/// a monitor test run to be valid.
4444
minimum_test_routes: usize,
45+
min_reliability: u8,
4546
}
4647

4748
impl Monitor {
@@ -66,14 +67,44 @@ impl Monitor {
6667
route_test_packets: config.get_route_test_packets(),
6768
test_routes: config.get_test_routes(),
6869
minimum_test_routes: config.get_minimum_test_routes(),
70+
min_reliability: config.get_min_reliability(),
6971
}
7072
}
7173

7274
// while it might have been cleaner to put this into a separate `Notifier` structure,
7375
// I don't see much point considering it's only a single, small, method
74-
async fn submit_new_node_statuses(&self, test_summary: TestSummary) {
76+
async fn submit_new_node_statuses(&mut self, test_summary: TestSummary) {
7577
// indicate our run has completed successfully and should be used in any future
7678
// uptime calculations
79+
80+
for result in test_summary.mixnode_results.iter() {
81+
if result.reliability < self.min_reliability {
82+
self.packet_preparer
83+
.validator_cache()
84+
.insert_mixnodes_blacklist(result.identity.clone())
85+
.await;
86+
} else {
87+
self.packet_preparer
88+
.validator_cache()
89+
.remove_mixnodes_blacklist(&result.identity)
90+
.await;
91+
}
92+
}
93+
94+
for result in test_summary.gateway_results.iter() {
95+
if result.reliability < self.min_reliability {
96+
self.packet_preparer
97+
.validator_cache()
98+
.insert_gateways_blacklist(result.identity.clone())
99+
.await;
100+
} else {
101+
self.packet_preparer
102+
.validator_cache()
103+
.remove_gateways_blacklist(&result.identity)
104+
.await;
105+
}
106+
}
107+
77108
if let Err(err) = self
78109
.node_status_storage
79110
.insert_monitor_run_results(

validator-api/src/network_monitor/monitor/preparer.rs

+14-12
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,10 @@ impl PacketPreparer {
150150
}
151151
}
152152

153+
pub fn validator_cache(&mut self) -> &mut ValidatorCache {
154+
&mut self.validator_cache
155+
}
156+
153157
async fn wrap_test_packet(
154158
&mut self,
155159
packet: &TestPacket,
@@ -187,7 +191,7 @@ impl PacketPreparer {
187191
let gateways = self.validator_cache.gateways().await;
188192
let mixnodes = self.validator_cache.rewarded_set().await;
189193

190-
if gateways.into_inner().len() < minimum_full_routes {
194+
if gateways.len() < minimum_full_routes {
191195
info!(
192196
"Minimal topology is still not online. Going to check again in {:?}",
193197
initialisation_backoff
@@ -224,11 +228,11 @@ impl PacketPreparer {
224228
}
225229
}
226230

227-
async fn get_rewarded_nodes(&self) -> (Vec<MixNodeBond>, Vec<GatewayBond>) {
231+
async fn all_mixnodes_and_gateways(&self) -> (Vec<MixNodeBond>, Vec<GatewayBond>) {
228232
info!(target: "Monitor", "Obtaining network topology...");
229233

230-
let mixnodes = self.validator_cache.rewarded_set().await.into_inner();
231-
let gateways = self.validator_cache.gateways().await.into_inner();
234+
let mixnodes = self.validator_cache.mixnodes_all().await;
235+
let gateways = self.validator_cache.gateways_all().await;
232236

233237
(mixnodes, gateways)
234238
}
@@ -262,19 +266,17 @@ impl PacketPreparer {
262266
n: usize,
263267
blacklist: &mut HashSet<String>,
264268
) -> Option<Vec<TestRoute>> {
265-
let rewarded_set = self.validator_cache.rewarded_set().await.into_inner();
266-
let gateways = self.validator_cache.gateways().await.into_inner();
267-
269+
let (mixnodes, gateways) = self.all_mixnodes_and_gateways().await;
268270
// separate mixes into layers for easier selection
269271
let mut layered_mixes = HashMap::new();
270-
for rewarded_mix in rewarded_set {
272+
for mix in mixnodes {
271273
// filter out mixes on the blacklist
272-
if blacklist.contains(&rewarded_mix.mix_node.identity_key) {
274+
if blacklist.contains(&mix.mix_node.identity_key) {
273275
continue;
274276
}
275-
let layer = rewarded_mix.layer;
277+
let layer = mix.layer;
276278
let mixes = layered_mixes.entry(layer).or_insert_with(Vec::new);
277-
mixes.push(rewarded_mix)
279+
mixes.push(mix)
278280
}
279281
// filter out gateways on the blacklist
280282
let gateways = gateways
@@ -458,7 +460,7 @@ impl PacketPreparer {
458460
// (remember that "idle" nodes are still part of that set)
459461
// we don't care about other nodes, i.e. nodes that are bonded but will not get
460462
// any reward during the current rewarding interval
461-
let (rewarded_set, all_gateways) = self.get_rewarded_nodes().await;
463+
let (rewarded_set, all_gateways) = self.all_mixnodes_and_gateways().await;
462464

463465
let (mixes, invalid_mixnodes) = self.filter_outdated_and_malformed_mixnodes(rewarded_set);
464466
let (gateways, invalid_gateways) =

validator-api/src/node_status_api/routes.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ pub(crate) async fn get_mixnode_inclusion_probability(
212212
cache: &State<ValidatorCache>,
213213
identity: String,
214214
) -> Json<Option<InclusionProbabilityResponse>> {
215-
let mixnodes = cache.mixnodes().await.into_inner();
215+
let mixnodes = cache.mixnodes().await;
216216

217217
if let Some(target_mixnode) = mixnodes.iter().find(|x| x.identity() == &identity) {
218218
let total_bonded_tokens = mixnodes

validator-api/src/rewarded_set_updater/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ impl RewardedSetUpdater {
204204
let epoch = self.epoch().await?;
205205
log::info!("Starting rewarded set update");
206206
// we know the entries are not stale, as a matter of fact they were JUST updated, since we got notified
207-
let all_nodes = self.validator_cache.mixnodes().await.into_inner();
207+
let all_nodes = self.validator_cache.mixnodes().await;
208208
let epoch_reward_params = self
209209
.validator_cache
210210
.epoch_reward_params()

0 commit comments

Comments
 (0)