Skip to content

Commit 5be91c7

Browse files
committed
feat: local blacklists
1 parent 8066637 commit 5be91c7

File tree

6 files changed

+199
-16
lines changed

6 files changed

+199
-16
lines changed

Makefile

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,17 @@ deploy:
129129
cd cli && cargo build --release --target=x86_64-unknown-linux-musl -p fledger && cargo build --release --target=x86_64-unknown-linux-musl -p flsignal
130130
@./deploy-binaries.sh
131131

132+
test_realm:
133+
/usr/bin/mktemp -d -t fledger-XXXX
134+
./target-common/x86_64-unknown-linux-musl/release/fledger --config "$(shell /usr/bin/mktemp -d -t fledger-XXXX)" --disable-turn-stun --signal-url ws://localhost:8765 realm create simulation --cond-pass
135+
136+
test_signal:
137+
./target-common/x86_64-unknown-linux-musl/release/flsignal -v --max-list-len 25
138+
139+
test_just_fetch_once:
140+
rm -rf /tmp/fledger
141+
./target-common/x86_64-unknown-linux-musl/release/fledger --config "$(shell /usr/bin/mktemp -d -t fledger-XXXX)" --disable-turn-stun --signal-url ws://localhost:8765 simulation just-fetch-once
142+
132143
clean:
133144
for c in ${CARGOS}; do \
134145
echo "Cleaning $$c"; \

cli/fledger/src/realm.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ impl RealmHandler {
4949
cond_pass: bool,
5050
) -> anyhow::Result<()> {
5151
f.loop_node(crate::FledgerState::Connected(1)).await?;
52+
//f.loop_node(crate::FledgerState::Duration(1)).await?;
5253

5354
let config = RealmConfig {
5455
max_space: max_space.unwrap_or(1000000),

cli/fledger/src/simulation.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,12 @@ pub enum SimulationSubcommand {
6363

6464
#[arg(long)]
6565
experiment_id: u32,
66+
67+
#[arg(long, default_value = "false")]
68+
with_local_blacklists: bool,
6669
},
70+
71+
JustFetchOnce {},
6772
}
6873

6974
pub struct SimulationHandler {}
@@ -108,6 +113,7 @@ impl SimulationHandler {
108113
timeout_ms,
109114
enable_sync,
110115
experiment_id,
116+
with_local_blacklists,
111117
} => {
112118
let evil_noforward = f.args.evil_noforward.clone();
113119
SimulationDht::run_fetch_pages(
@@ -118,9 +124,11 @@ impl SimulationHandler {
118124
timeout_ms,
119125
experiment_id,
120126
evil_noforward,
127+
with_local_blacklists,
121128
)
122129
.await
123130
}
131+
SimulationSubcommand::JustFetchOnce {} => SimulationDht::just_fetch_once(f).await,
124132
}
125133
}
126134
}

cli/fledger/src/simulation_dht/simulation.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,9 +186,18 @@ impl SimulationDht {
186186
timeout_ms: u32,
187187
experiment_id: u32,
188188
evil_noforward: bool,
189+
with_local_blacklists: bool,
189190
) -> anyhow::Result<()> {
190191
let mut start_instant = Instant::now();
191192

193+
unsafe {
194+
if with_local_blacklists {
195+
log::info!("enabling local blacklists");
196+
flmodules::dht_storage::messages::LOCAL_BLACKLISTS = true;
197+
flmodules::dht_router::messages::LOCAL_BLACKLISTS = true;
198+
}
199+
}
200+
192201
let node_name = f.node.node_config.info.name.clone();
193202
let mut state = SimulationState::new(experiment_id, node_name);
194203

@@ -301,4 +310,34 @@ impl SimulationDht {
301310
}
302311
}
303312
}
313+
314+
pub async fn just_fetch_once(mut f: Fledger) -> anyhow::Result<()> {
315+
f.loop_node(crate::FledgerState::DHTAvailable).await?;
316+
f.loop_node(crate::FledgerState::Connected(2)).await?;
317+
318+
let realm_id = RealmView::new_first(f.node.dht_storage.as_ref().unwrap().clone())
319+
.await?
320+
.realm
321+
.realm_id();
322+
323+
let flo_id =
324+
FloID::from_str("5efe0a6143df5641af9d6036ba8da82222bb30211c21ba5ec236851efda38420")?;
325+
let global_page_id = Self::make_page_id(realm_id.clone(), flo_id);
326+
327+
for i in 0..10 {
328+
wait_ms(1000).await;
329+
330+
let page = Self::fetch_page(&mut f, global_page_id.clone()).await;
331+
332+
if page.is_ok() {
333+
log::info!("God made a miracle");
334+
} else {
335+
log::info!("Fetch {i} done.");
336+
}
337+
}
338+
339+
f.loop_node(crate::FledgerState::Forever).await?;
340+
341+
Ok(())
342+
}
304343
}

flmodules/src/dht_router/messages.rs

Lines changed: 129 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
1+
use std::collections::{HashMap, HashSet};
2+
13
use flarch::{
24
broker::{SubsystemHandler, TranslateFrom, TranslateInto},
35
nodeids::{NodeID, U256},
46
platform_async_trait,
57
};
6-
use rand::seq::SliceRandom;
8+
use itertools::Itertools;
9+
use rand::{seq::SliceRandom, Rng};
710
use serde::{Deserialize, Serialize};
811
use tokio::sync::watch;
912

1013
use crate::{
14+
dht_storage::messages::MessageClosest,
1115
nodeconfig::NodeInfo,
1216
router::messages::{NetworkWrapper, RouterIn, RouterOut},
1317
timer::TimerMessage,
@@ -19,6 +23,7 @@ use super::{
1923
};
2024

2125
pub static mut EVIL_NO_FORWARD: bool = false;
26+
pub static mut LOCAL_BLACKLISTS: bool = false;
2227

2328
/// These are the messages which will be exchanged between the nodes for this
2429
/// module.
@@ -73,6 +78,11 @@ pub(super) struct Messages {
7378
// This is different than core.active, because there can be connections from other
7479
// modules, or connections from another node.
7580
connected: Vec<NodeID>,
81+
82+
// readFlo id -> node id
83+
requests_in_flight: HashMap<U256, U256>,
84+
85+
blacklisted_nodes: HashSet<U256>,
7686
}
7787

7888
impl Messages {
@@ -84,6 +94,8 @@ impl Messages {
8494
core: Kademlia::new(root, cfg),
8595
tx: Some(tx),
8696
connected: vec![],
97+
requests_in_flight: HashMap::new(),
98+
blacklisted_nodes: HashSet::new(),
8799
},
88100
rx,
89101
)
@@ -233,22 +245,131 @@ impl Messages {
233245
}
234246
}
235247

248+
fn get_readflo_id(&self, msg: NetworkWrapper) -> Option<U256> {
249+
if msg.module == "DHTStorage" {
250+
match msg.unwrap_yaml("DHTStorage") {
251+
Some(msg_readflo) => match msg_readflo {
252+
MessageClosest::ReadFlo(_id, request_id) => {
253+
log::warn!("sending MessageClosest::ReadFlo {}", msg.msg.clone());
254+
Some(request_id.clone())
255+
}
256+
_ => None,
257+
},
258+
None => None,
259+
}
260+
} else {
261+
None
262+
}
263+
}
264+
265+
fn blacklist_bad_nodes(&mut self) {
266+
unsafe {
267+
if !self::LOCAL_BLACKLISTS {
268+
return;
269+
}
270+
}
271+
272+
let in_flight = self.requests_in_flight.clone();
273+
in_flight
274+
.iter()
275+
.map(|(_request_id, node_id)| node_id)
276+
.counts()
277+
.iter()
278+
.for_each(|(node_id_request, count)| {
279+
let node_id1 = (*node_id_request).clone();
280+
if count.clone() > 10 {
281+
// made 10 requests to this node
282+
// remove the node from requests_in_flight to reset the counter
283+
// and blacklist the node
284+
log::warn!("blacklisting {node_id1}.");
285+
let request_ids = self
286+
.requests_in_flight
287+
.clone()
288+
.iter()
289+
.filter(|(_request_id, node_id2)| node_id1 == **node_id2)
290+
.map(|(request_id, _node_id)| request_id)
291+
.copied()
292+
.collect_vec();
293+
for value in request_ids {
294+
self.requests_in_flight.remove_entry(&value);
295+
}
296+
self.core.remove_node(&node_id1);
297+
self.blacklisted_nodes.insert(node_id1);
298+
}
299+
});
300+
}
301+
302+
fn randomly_whitelist(&mut self) {
303+
unsafe {
304+
if !self::LOCAL_BLACKLISTS {
305+
return;
306+
}
307+
}
308+
309+
let mut rng = rand::thread_rng();
310+
if !self.blacklisted_nodes.is_empty() && rng.gen_bool(0.05) {
311+
let len = self.blacklisted_nodes.len();
312+
if len > 0 {
313+
let random_index = rng.gen_range(0..len);
314+
let node_id_opt = self.blacklisted_nodes.iter().nth(random_index).clone();
315+
if let Some(node_id) = node_id_opt {
316+
log::warn!("whitelisting {node_id}.");
317+
self.core.add_node(node_id.clone());
318+
self.blacklisted_nodes.remove(&(node_id.clone()));
319+
}
320+
}
321+
}
322+
}
323+
324+
fn log_requests_in_flight(&self) {
325+
log::info!("counts:");
326+
self.requests_in_flight
327+
.iter()
328+
.map(|tuple| tuple.1)
329+
.counts()
330+
.iter()
331+
.for_each(|item| log::info!(" {} -> {}", item.0, item.1))
332+
}
333+
236334
fn message_closest(
237-
&self,
335+
&mut self,
238336
orig: NodeID,
239337
last_hop: NodeID,
240338
key: U256,
241339
msg: NetworkWrapper,
242340
) -> Vec<InternOut> {
243-
match self
341+
let readflo_id_opt = self.get_readflo_id(msg.clone());
342+
343+
self.blacklist_bad_nodes();
344+
345+
let closest = self
244346
.closest_or_connected(key.clone(), Some(&last_hop))
245347
.first()
246-
{
247-
Some(&next_hop) => vec![
248-
ModuleMessage::Closest(orig, key, msg.clone()).wrapper_network(next_hop),
249-
DHTRouterOut::MessageRouting(orig, last_hop, next_hop, key, msg).into(),
250-
],
348+
.copied();
349+
350+
self.randomly_whitelist();
351+
352+
match closest.clone() {
353+
Some(next_hop) => {
354+
if self.blacklisted_nodes.contains(&next_hop) {
355+
log::error!("IMPOSSIBLE?: sending a message to a blacklisted node.");
356+
}
357+
358+
if let Some(readflo_id) = readflo_id_opt {
359+
log::info!("NEXT HOP: {}", next_hop);
360+
self.requests_in_flight
361+
.insert(readflo_id.clone(), next_hop.clone());
362+
self.log_requests_in_flight();
363+
}
364+
vec![
365+
ModuleMessage::Closest(orig, key, msg.clone()).wrapper_network(next_hop),
366+
DHTRouterOut::MessageRouting(orig, last_hop, next_hop, key, msg).into(),
367+
]
368+
}
251369
None => {
370+
if readflo_id_opt.is_some() {
371+
log::warn!("NO NEXT HOP!");
372+
}
252373
if key == self.core.root {
253374
vec![DHTRouterOut::MessageDest(orig, last_hop, msg).into()]
254375
} else {

flmodules/src/dht_storage/messages.rs

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ pub enum MessageClosest {
4747
// which have enough place left.
4848
StoreFlo(Flo),
4949
// Request a Flo. The FloID is in the DHTRouting::Request.
50-
ReadFlo(RealmID),
50+
// The U256 is a random id identifying this specific request
51+
ReadFlo(RealmID, U256),
5152
// Request Cuckoos for the given ID. The FloID is in the DHTRouting::Request.
5253
GetCuckooIDs(RealmID),
5354
// Store the Cuckoo-ID in the relevant Flo. The DHTRouting::Request(key) is the
@@ -61,7 +62,8 @@ pub enum MessageClosest {
6162
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
6263
pub enum MessageDest {
6364
// Returns the result of the requested Flo, including any available Cuckoo-IDs.
64-
FloValue(FloCuckoo),
65+
// The optional u256 is an optional identifier of the readflo request id
66+
FloValue(FloCuckoo, Option<U256>),
6567
// Indicates this Flo is not in the closest node.
6668
UnknownFlo(GlobalID),
6769
// The Cuckoo-IDs stored next to the Flo composed of the GlobalID
@@ -154,6 +156,7 @@ pub struct Messages {
154156
}
155157

156158
pub static mut EVIL_NO_FORWARD: bool = false;
159+
pub static mut LOCAL_BLACKLISTS: bool = false;
157160

158161
impl Messages {
159162
/// Returns a new simulation_chat module.
@@ -213,7 +216,7 @@ impl Messages {
213216
DHTStorageIn::StoreFlo(flo) => self.store_flo(flo),
214217
DHTStorageIn::ReadFlo(id) => vec![match self.read_flo(&id) {
215218
Some(df) => DHTStorageOut::FloValue(df.clone()).into(),
216-
None => MessageClosest::ReadFlo(id.realm_id().clone())
219+
None => MessageClosest::ReadFlo(id.realm_id().clone(), U256::rnd())
217220
.to_intern_out(id.flo_id().clone().into())
218221
// .inspect(|msg| log::info!("{} sends {msg:?}", self.our_id))
219222
.expect("Creating ReadFlo message"),
@@ -262,7 +265,7 @@ impl Messages {
262265
MessageClosest::StoreFlo(flo) => {
263266
return self.store_flo(flo);
264267
}
265-
MessageClosest::ReadFlo(rid) => {
268+
MessageClosest::ReadFlo(rid, request_id) => {
266269
// log::info!(
267270
// "{} got request for {}/{} from {}",
268271
// self.our_id,
@@ -279,7 +282,7 @@ impl Messages {
279282
// log::info!("sends flo {:?}", fc.0);
280283
if unsafe { !EVIL_NO_FORWARD } {
281284
increment_stat!(self, self.experiment_stats.flo_value_sent_total);
282-
return MessageDest::FloValue(fc)
285+
return MessageDest::FloValue(fc, Some(request_id))
283286
.to_intern_out(origin)
284287
// .inspect(|msg| log::info!("{} sends {msg:?}", self.our_id))
285288
.map_or(vec![], |msg| vec![msg]);
@@ -312,7 +315,7 @@ impl Messages {
312315

313316
fn msg_dest(&mut self, msg: MessageDest) -> Vec<InternOut> {
314317
match msg {
315-
MessageDest::FloValue(fc) => {
318+
MessageDest::FloValue(fc, _) => {
316319
// log::info!("{} stores {:?}", self.our_id, flo.0);
317320
self.store_flo(fc.0.clone());
318321
self.realms
@@ -723,11 +726,11 @@ mod tests {
723726

724727
let out = NetworkWrapper::wrap_yaml(
725728
MODULE_NAME,
726-
&MessageDest::FloValue((fr.flo().clone(), vec![])),
729+
&MessageDest::FloValue((fr.flo().clone(), vec![]), None),
727730
)
728731
.unwrap();
729732

730-
if let MessageDest::FloValue(flo) = out.unwrap_yaml(MODULE_NAME).unwrap() {
733+
if let MessageDest::FloValue(flo, _) = out.unwrap_yaml(MODULE_NAME).unwrap() {
731734
let fr2 = TryInto::<FloRealm>::try_into(flo.0)?;
732735
assert_eq!(fr, fr2);
733736
} else {

0 commit comments

Comments
 (0)