proto.rs 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2025 Dyne.org foundation
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Affero General Public License as
  7. * published by the Free Software Foundation, either version 3 of the
  8. * License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU Affero General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. use std::{
  19. collections::{BTreeMap, HashSet, VecDeque},
  20. sync::{
  21. atomic::{AtomicUsize, Ordering::SeqCst},
  22. Arc,
  23. },
  24. };
  25. use darkfi_serial::{async_trait, SerialDecodable, SerialEncodable};
  26. use log::{debug, error, trace, warn};
  27. use smol::Executor;
  28. use super::{Event, EventGraphPtr, NULL_ID};
  29. use crate::{
  30. impl_p2p_message,
  31. net::{
  32. metering::{MeteringConfiguration, DEFAULT_METERING_CONFIGURATION},
  33. ChannelPtr, Message, MessageSubscription, ProtocolBase, ProtocolBasePtr,
  34. ProtocolJobsManager, ProtocolJobsManagerPtr,
  35. },
  36. system::msleep,
  37. util::time::NanoTimestamp,
  38. Error, Result,
  39. };
  40. /// Malicious behaviour threshold. If the threshold is reached, we will
  41. /// drop the peer from our P2P connection.
  42. const MALICIOUS_THRESHOLD: usize = 5;
  43. /// Global limit of messages per window
  44. const WINDOW_MAXSIZE: usize = 200;
  45. /// Rolling length of the window
  46. const WINDOW_EXPIRY_TIME: NanoTimestamp = NanoTimestamp::from_secs(60);
  47. /// Rolling length of the window
  48. const RATELIMIT_EXPIRY_TIME: NanoTimestamp = NanoTimestamp::from_secs(10);
  49. /// Ratelimit kicks in above this count
  50. const RATELIMIT_MIN_COUNT: usize = 6;
  51. /// Sample point used to calculate sleep time when ratelimit is active
  52. const RATELIMIT_SAMPLE_IDX: usize = 10;
  53. /// Sleep for this amount of time when `count == RATE_LIMIT_SAMPLE_IDX`.
  54. const RATELIMIT_SAMPLE_SLEEP: usize = 1000;
  55. struct MovingWindow {
  56. times: VecDeque<NanoTimestamp>,
  57. expiry_time: NanoTimestamp,
  58. }
  59. impl MovingWindow {
  60. fn new(expiry_time: NanoTimestamp) -> Self {
  61. Self { times: VecDeque::new(), expiry_time }
  62. }
  63. /// Clean out expired timestamps from the window.
  64. fn clean(&mut self) {
  65. while let Some(ts) = self.times.front() {
  66. let Ok(elapsed) = ts.elapsed() else {
  67. debug!(target: "event_graph::protocol::MovingWindow::clean()", "Timestamp [{}] is in future. Removing...", ts);
  68. let _ = self.times.pop_front();
  69. continue
  70. };
  71. if elapsed < self.expiry_time {
  72. break
  73. }
  74. let _ = self.times.pop_front();
  75. }
  76. }
  77. /// Add new timestamp
  78. fn ticktock(&mut self) {
  79. self.clean();
  80. self.times.push_back(NanoTimestamp::current_time());
  81. }
  82. #[inline]
  83. fn count(&self) -> usize {
  84. self.times.len()
  85. }
  86. }
  87. /// P2P protocol implementation for the Event Graph.
  88. pub struct ProtocolEventGraph {
  89. /// Pointer to the connected peer
  90. channel: ChannelPtr,
  91. /// Pointer to the Event Graph instance
  92. event_graph: EventGraphPtr,
  93. /// `MessageSubscriber` for `EventPut`
  94. ev_put_sub: MessageSubscription<EventPut>,
  95. /// `MessageSubscriber` for `EventReq`
  96. ev_req_sub: MessageSubscription<EventReq>,
  97. /// `MessageSubscriber` for `EventRep`
  98. ev_rep_sub: MessageSubscription<EventRep>,
  99. /// `MessageSubscriber` for `TipReq`
  100. tip_req_sub: MessageSubscription<TipReq>,
  101. /// `MessageSubscriber` for `TipRep`
  102. _tip_rep_sub: MessageSubscription<TipRep>,
  103. /// Peer malicious message count
  104. malicious_count: AtomicUsize,
  105. /// P2P jobs manager pointer
  106. jobsman: ProtocolJobsManagerPtr,
  107. /// To apply the rate-limit, we don't broadcast directly but instead send into the
  108. /// sending queue.
  109. broadcaster_push: smol::channel::Sender<EventPut>,
  110. /// Receive send requests and rate-limit broadcasting them.
  111. broadcaster_pull: smol::channel::Receiver<EventPut>,
  112. }
  113. /// A P2P message representing publishing an event on the network
  114. #[derive(Clone, SerialEncodable, SerialDecodable)]
  115. pub struct EventPut(pub Event);
  116. impl_p2p_message!(EventPut, "EventGraph::EventPut", 0, 0, DEFAULT_METERING_CONFIGURATION);
  117. /// A P2P message representing an event request
  118. #[derive(Clone, SerialEncodable, SerialDecodable)]
  119. pub struct EventReq(pub Vec<blake3::Hash>);
  120. impl_p2p_message!(EventReq, "EventGraph::EventReq", 0, 0, DEFAULT_METERING_CONFIGURATION);
  121. /// A P2P message representing an event reply
  122. #[derive(Clone, SerialEncodable, SerialDecodable)]
  123. pub struct EventRep(pub Vec<Event>);
  124. impl_p2p_message!(EventRep, "EventGraph::EventRep", 0, 0, DEFAULT_METERING_CONFIGURATION);
  125. /// A P2P message representing a request for a peer's DAG tips
  126. #[derive(Clone, SerialEncodable, SerialDecodable)]
  127. pub struct TipReq {}
  128. impl_p2p_message!(TipReq, "EventGraph::TipReq", 0, 0, DEFAULT_METERING_CONFIGURATION);
  129. /// A P2P message representing a reply for the peer's DAG tips
  130. #[derive(Clone, SerialEncodable, SerialDecodable)]
  131. pub struct TipRep(pub BTreeMap<u64, HashSet<blake3::Hash>>);
  132. impl_p2p_message!(TipRep, "EventGraph::TipRep", 0, 0, DEFAULT_METERING_CONFIGURATION);
  133. #[async_trait]
  134. impl ProtocolBase for ProtocolEventGraph {
  135. async fn start(self: Arc<Self>, ex: Arc<Executor<'_>>) -> Result<()> {
  136. self.jobsman.clone().start(ex.clone());
  137. self.jobsman.clone().spawn(self.clone().handle_event_put(), ex.clone()).await;
  138. self.jobsman.clone().spawn(self.clone().handle_event_req(), ex.clone()).await;
  139. self.jobsman.clone().spawn(self.clone().handle_tip_req(), ex.clone()).await;
  140. self.jobsman.clone().spawn(self.clone().broadcast_rate_limiter(), ex.clone()).await;
  141. Ok(())
  142. }
  143. fn name(&self) -> &'static str {
  144. "ProtocolEventGraph"
  145. }
  146. }
  147. impl ProtocolEventGraph {
  148. pub async fn init(event_graph: EventGraphPtr, channel: ChannelPtr) -> Result<ProtocolBasePtr> {
  149. let msg_subsystem = channel.message_subsystem();
  150. msg_subsystem.add_dispatch::<EventPut>().await;
  151. msg_subsystem.add_dispatch::<EventReq>().await;
  152. msg_subsystem.add_dispatch::<EventRep>().await;
  153. msg_subsystem.add_dispatch::<TipReq>().await;
  154. msg_subsystem.add_dispatch::<TipRep>().await;
  155. let ev_put_sub = channel.subscribe_msg::<EventPut>().await?;
  156. let ev_req_sub = channel.subscribe_msg::<EventReq>().await?;
  157. let ev_rep_sub = channel.subscribe_msg::<EventRep>().await?;
  158. let tip_req_sub = channel.subscribe_msg::<TipReq>().await?;
  159. let _tip_rep_sub = channel.subscribe_msg::<TipRep>().await?;
  160. let (broadcaster_push, broadcaster_pull) = smol::channel::unbounded();
  161. Ok(Arc::new(Self {
  162. channel: channel.clone(),
  163. event_graph,
  164. ev_put_sub,
  165. ev_req_sub,
  166. ev_rep_sub,
  167. tip_req_sub,
  168. _tip_rep_sub,
  169. malicious_count: AtomicUsize::new(0),
  170. jobsman: ProtocolJobsManager::new("ProtocolEventGraph", channel.clone()),
  171. broadcaster_push,
  172. broadcaster_pull,
  173. }))
  174. }
  175. async fn increase_malicious_count(self: Arc<Self>) -> Result<()> {
  176. let malicious_count = self.malicious_count.fetch_add(1, SeqCst);
  177. if malicious_count + 1 == MALICIOUS_THRESHOLD {
  178. error!(
  179. target: "event_graph::protocol::handle_event_put()",
  180. "[EVENTGRAPH] Peer {} reached malicious threshold. Dropping connection.",
  181. self.channel.address(),
  182. );
  183. self.channel.stop().await;
  184. return Err(Error::ChannelStopped)
  185. }
  186. warn!(
  187. target: "event_graph::protocol::handle_event_put()",
  188. "[EVENTGRAPH] Peer {} sent us a malicious event", self.channel.address(),
  189. );
  190. Ok(())
  191. }
  192. /// Protocol function handling `EventPut`.
  193. /// This is triggered whenever someone broadcasts (or relays) a new
  194. /// event on the network.
  195. async fn handle_event_put(self: Arc<Self>) -> Result<()> {
  196. // Rolling window of event timestamps on this channel
  197. let mut bantimes = MovingWindow::new(WINDOW_EXPIRY_TIME);
  198. loop {
  199. let event = match self.ev_put_sub.receive().await {
  200. Ok(v) => v.0.clone(),
  201. Err(_) => continue,
  202. };
  203. trace!(
  204. target: "event_graph::protocol::handle_event_put()",
  205. "Got EventPut: {} [{}]", event.id(), self.channel.address(),
  206. );
  207. // Check if node has finished syncing its DAG
  208. if !*self.event_graph.synced.read().await {
  209. debug!(
  210. target: "event_graph::protocol::handle_event_put",
  211. "DAG is still syncing, skipping..."
  212. );
  213. continue
  214. }
  215. // If we have already seen the event, we'll stay quiet.
  216. let event_id = event.id();
  217. if self.event_graph.dag.contains_key(event_id.as_bytes()).unwrap() {
  218. debug!(
  219. target: "event_graph::protocol::handle_event_put()",
  220. "Event {} is already known", event_id,
  221. );
  222. continue
  223. }
  224. // There's a new unique event.
  225. // Apply ban logic to stop network floods.
  226. bantimes.ticktock();
  227. if bantimes.count() > WINDOW_MAXSIZE {
  228. self.channel.ban().await;
  229. // This error is actually unused. We could return Ok here too.
  230. return Err(Error::MaliciousFlood)
  231. }
  232. // We received an event. Check if we already have it in our DAG.
  233. // Check event is not older that current genesis event timestamp.
  234. // Also check if we have the event's parents. In the case we do
  235. // not have the parents, we'll request them from the peer that has
  236. // sent this event to us. In case they do not reply in time, we drop
  237. // the event.
  238. // Check if the event is older than the genesis event. If so, we should
  239. // not include it in our Dag.
  240. // The genesis event marks the last time the Dag has been pruned of old
  241. // events. The pruning interval is defined by the days_rotation field
  242. // of [`EventGraph`].
  243. let genesis_timestamp = self.event_graph.current_genesis.read().await.timestamp;
  244. if event.timestamp < genesis_timestamp {
  245. debug!(
  246. target: "event_graph::protocol::handle_event_put()",
  247. "Event {} is older than genesis. Event timestamp: `{}`. Genesis timestamp: `{}`",
  248. event.id(), event.timestamp, genesis_timestamp
  249. );
  250. }
  251. // Validate the new event first. If we do not consider it valid, we
  252. // will just drop it and stay quiet. If the malicious threshold
  253. // is reached, we will stop the connection.
  254. if !event.validate_new() {
  255. self.clone().increase_malicious_count().await?;
  256. continue
  257. }
  258. // At this point, this is a new event to us. Let's see if we
  259. // have all of its parents.
  260. debug!(
  261. target: "event_graph::protocol::handle_event_put()",
  262. "Event {} is new", event_id,
  263. );
  264. let mut missing_parents = HashSet::new();
  265. for parent_id in event.parents.iter() {
  266. // `event.validate_new()` should have already made sure that
  267. // not all parents are NULL, and that there are no duplicates.
  268. if parent_id == &NULL_ID {
  269. continue
  270. }
  271. if !self.event_graph.dag.contains_key(parent_id.as_bytes()).unwrap() {
  272. missing_parents.insert(*parent_id);
  273. }
  274. }
  275. // If we have missing parents, then we have to attempt to
  276. // fetch them from this peer. Do this recursively until we
  277. // find all of them.
  278. if !missing_parents.is_empty() {
  279. // We track the received events mapped by their layer.
  280. // If/when we get all of them, we need to insert them in order so
  281. // the DAG state stays correct and unreferenced tips represent the
  282. // actual thing they should. If we insert them out of order, then
  283. // we might have wrong unreferenced tips.
  284. let mut received_events: BTreeMap<u64, Vec<Event>> = BTreeMap::new();
  285. let mut received_events_hashes = HashSet::new();
  286. debug!(
  287. target: "event_graph::protocol::handle_event_put()",
  288. "Event has {} missing parents. Requesting...", missing_parents.len(),
  289. );
  290. while !missing_parents.is_empty() {
  291. // for parent_id in missing_parents.clone().iter() {
  292. debug!(
  293. target: "event_graph::protocol::handle_event_put()",
  294. "Requesting {:?}...", missing_parents,
  295. );
  296. self.channel
  297. .send(&EventReq(missing_parents.clone().into_iter().collect()))
  298. .await?;
  299. // Node waits for response
  300. let Ok(parents) = self
  301. .ev_rep_sub
  302. .receive_with_timeout(
  303. self.event_graph.p2p.settings().read().await.outbound_connect_timeout,
  304. )
  305. .await
  306. else {
  307. error!(
  308. target: "event_graph::protocol::handle_event_put()",
  309. "[EVENTGRAPH] Timeout while waiting for parents {:?} from {}",
  310. missing_parents, self.channel.address(),
  311. );
  312. self.channel.stop().await;
  313. return Err(Error::ChannelStopped)
  314. };
  315. let parents = parents.0.clone();
  316. for parent in parents {
  317. let parent_id = parent.id();
  318. if !missing_parents.contains(&parent_id) {
  319. error!(
  320. target: "event_graph::protocol::handle_event_put()",
  321. "[EVENTGRAPH] Peer {} replied with a wrong event: {}",
  322. self.channel.address(), parent.id(),
  323. );
  324. self.channel.stop().await;
  325. return Err(Error::ChannelStopped)
  326. }
  327. debug!(
  328. target: "event_graph::protocol::handle_event_put()",
  329. "Got correct parent event {}", parent.id(),
  330. );
  331. if let Some(layer_events) = received_events.get_mut(&parent.layer) {
  332. layer_events.push(parent.clone());
  333. } else {
  334. let layer_events = vec![parent.clone()];
  335. received_events.insert(parent.layer, layer_events);
  336. }
  337. received_events_hashes.insert(parent_id);
  338. missing_parents.remove(&parent_id);
  339. // See if we have the upper parents
  340. for upper_parent in parent.parents.iter() {
  341. if upper_parent == &NULL_ID {
  342. continue
  343. }
  344. if !missing_parents.contains(upper_parent) &&
  345. !received_events_hashes.contains(upper_parent) &&
  346. !self
  347. .event_graph
  348. .dag
  349. .contains_key(upper_parent.as_bytes())
  350. .unwrap()
  351. {
  352. debug!(
  353. target: "event_graph::protocol::handle_event_put()",
  354. "Found upper missing parent event {}", upper_parent,
  355. );
  356. missing_parents.insert(*upper_parent);
  357. }
  358. }
  359. }
  360. } // <-- while !missing_parents.is_empty()
  361. // At this point we should've got all the events.
  362. // We should add them to the DAG.
  363. let mut events = vec![];
  364. for (_, tips) in received_events {
  365. for tip in tips {
  366. events.push(tip);
  367. }
  368. }
  369. if self.event_graph.dag_insert(&events).await.is_err() {
  370. self.clone().increase_malicious_count().await?;
  371. continue
  372. }
  373. } // <-- !missing_parents.is_empty()
  374. // If we're here, we have all the parents, and we can now
  375. // perform a full validation and add the actual event to
  376. // the DAG.
  377. debug!(
  378. target: "event_graph::protocol::handle_event_put()",
  379. "Got all parents necessary for insertion",
  380. );
  381. if self.event_graph.dag_insert(&[event.clone()]).await.is_err() {
  382. self.clone().increase_malicious_count().await?;
  383. continue
  384. }
  385. self.broadcaster_push.send(EventPut(event)).await.expect("push broadcaster closed");
  386. }
  387. }
  388. /// Protocol function handling `EventReq`.
  389. /// This is triggered whenever someone requests an event from us.
  390. async fn handle_event_req(self: Arc<Self>) -> Result<()> {
  391. loop {
  392. let event_ids = match self.ev_req_sub.receive().await {
  393. Ok(v) => v.0.clone(),
  394. Err(_) => continue,
  395. };
  396. trace!(
  397. target: "event_graph::protocol::handle_event_req()",
  398. "Got EventReq: {:?} [{}]", event_ids, self.channel.address(),
  399. );
  400. // Check if node has finished syncing its DAG
  401. if !*self.event_graph.synced.read().await {
  402. debug!(
  403. target: "event_graph::protocol::handle_event_req()",
  404. "DAG is still syncing, skipping..."
  405. );
  406. continue
  407. }
  408. // We received an event request from somebody.
  409. // If we do have it, we will send it back to them as `EventRep`.
  410. // Otherwise, we'll stay quiet. An honest node should always have
  411. // something to reply with provided that the request is legitimate,
  412. // i.e. we've sent something to them and they did not have some of
  413. // the parents.
  414. // Check if we expected this request to come around.
  415. // I dunno if this is a good idea, but it seems it will help
  416. // against malicious event requests where they want us to keep
  417. // reading our db and steal our bandwidth.
  418. let mut events = vec![];
  419. for event_id in event_ids.iter() {
  420. if !self.event_graph.broadcasted_ids.read().await.contains(event_id) {
  421. let malicious_count = self.malicious_count.fetch_add(1, SeqCst);
  422. if malicious_count + 1 == MALICIOUS_THRESHOLD {
  423. error!(
  424. target: "event_graph::protocol::handle_event_req()",
  425. "[EVENTGRAPH] Peer {} reached malicious threshold. Dropping connection.",
  426. self.channel.address(),
  427. );
  428. self.channel.stop().await;
  429. return Err(Error::ChannelStopped)
  430. }
  431. warn!(
  432. target: "event_graph::protocol::handle_event_req()",
  433. "[EVENTGRAPH] Peer {} requested an unexpected event {:?}",
  434. self.channel.address(), event_id,
  435. );
  436. continue
  437. }
  438. // At this point we should have it in our DAG.
  439. // This code panics if this is not the case.
  440. debug!(
  441. target: "event_graph::protocol::handle_event_req()",
  442. "Fetching event {:?} from DAG", event_id,
  443. );
  444. events.push(self.event_graph.dag_get(event_id).await.unwrap().unwrap());
  445. }
  446. // Check if the incoming event is older than the genesis event. If so, something
  447. // has gone wrong. The event should have been pruned during the last
  448. // rotation.
  449. let genesis_timestamp = self.event_graph.current_genesis.read().await.timestamp;
  450. let mut bcast_ids = self.event_graph.broadcasted_ids.write().await;
  451. for event in events.iter() {
  452. if event.timestamp < genesis_timestamp {
  453. error!(
  454. target: "event_graph::protocol::handle_event_req()",
  455. "Requested event by peer {} is older than previous rotation period. It should have been pruned.
  456. Event timestamp: `{}`. Genesis timestamp: `{}`",
  457. event.id(), event.timestamp, genesis_timestamp
  458. );
  459. }
  460. // Now let's get the upper level of event IDs. When we reply, we could
  461. // get requests for those IDs as well.
  462. for parent_id in event.parents.iter() {
  463. if parent_id != &NULL_ID {
  464. bcast_ids.insert(*parent_id);
  465. }
  466. }
  467. }
  468. // TODO: We should remove the reply from the bcast IDs for this specific channel.
  469. // We can't remove them for everyone.
  470. //bcast_ids.remove(&event_id);
  471. drop(bcast_ids);
  472. // Reply with the event
  473. self.channel.send(&EventRep(events)).await?;
  474. }
  475. }
  476. /// Protocol function handling `TipReq`.
  477. /// This is triggered when someone requests the current unreferenced
  478. /// tips of our DAG.
  479. async fn handle_tip_req(self: Arc<Self>) -> Result<()> {
  480. loop {
  481. self.tip_req_sub.receive().await?;
  482. trace!(
  483. target: "event_graph::protocol::handle_tip_req()",
  484. "Got TipReq [{}]", self.channel.address(),
  485. );
  486. // Check if node has finished syncing its DAG
  487. if !*self.event_graph.synced.read().await {
  488. debug!(
  489. target: "event_graph::protocol::handle_tip_req()",
  490. "DAG is still syncing, skipping..."
  491. );
  492. continue
  493. }
  494. // TODO: Rate limit
  495. // We received a tip request. Let's find them, add them to
  496. // our bcast ids list, and reply with them.
  497. let layers = self.event_graph.unreferenced_tips.read().await.clone();
  498. let mut bcast_ids = self.event_graph.broadcasted_ids.write().await;
  499. for (_, tips) in layers.iter() {
  500. for tip in tips {
  501. bcast_ids.insert(*tip);
  502. }
  503. }
  504. drop(bcast_ids);
  505. self.channel.send(&TipRep(layers)).await?;
  506. }
  507. }
  508. /// We need to rate limit message propagation so malicious nodes don't get us banned
  509. /// for flooding. We do that by aggregating messages here into a queue then apply
  510. /// rate limit logic before broadcasting.
  511. ///
  512. /// The rate limit logic is this:
  513. ///
  514. /// * If the count is less then RATELIMIT_MIN_COUNT then do nothing.
  515. /// * Otherwise sleep for `sleep_time` ms.
  516. ///
  517. /// To calculate the sleep time, we use the RATELIMIT_SAMPLE_* values.
  518. /// For example RATELIMIT_SAMPLE_IDX = 10, RATELIMIT_SAMPLE_SLEEP = 1000
  519. /// means that when N = 10, then sleep for 1000 ms.
  520. ///
  521. /// Let RATELIMIT_MIN_COUNT = 6, then here's a table of sleep times:
  522. ///
  523. /// | Count | Sleep Time / ms |
  524. /// |-------|-----------------|
  525. /// | 0 | 0 |
  526. /// | 4 | 0 |
  527. /// | 6 | 0 |
  528. /// | 10 | 1000 |
  529. /// | 14 | 2000 |
  530. /// | 18 | 3000 |
  531. ///
  532. /// So we use the sample to calculate a straight line from RATELIMIT_MIN_COUNT.
  533. async fn broadcast_rate_limiter(self: Arc<Self>) -> Result<()> {
  534. let mut ratelimit = MovingWindow::new(RATELIMIT_EXPIRY_TIME);
  535. loop {
  536. let event_put = self.broadcaster_pull.recv().await.expect("pull broadcaster closed");
  537. ratelimit.ticktock();
  538. if ratelimit.count() > RATELIMIT_MIN_COUNT {
  539. let sleep_time =
  540. ((ratelimit.count() - RATELIMIT_MIN_COUNT) * RATELIMIT_SAMPLE_SLEEP /
  541. (RATELIMIT_SAMPLE_IDX - RATELIMIT_MIN_COUNT)) as u64;
  542. debug!(
  543. target: "event_graph::protocol::broadcast_rate_limiter",
  544. "Activated rate limit: sleeping {sleep_time} ms [count={}]",
  545. ratelimit.count()
  546. );
  547. // Apply the ratelimit
  548. msleep(sleep_time).await;
  549. }
  550. // Relay the event to other peers.
  551. self.event_graph
  552. .p2p
  553. .broadcast_with_exclude(&event_put, &[self.channel.address().clone()])
  554. .await;
  555. }
  556. }
  557. }
  558. #[cfg(test)]
  559. mod test {
  560. use super::*;
  561. use std::time::UNIX_EPOCH;
  562. #[test]
  563. fn test_eventgraph_moving_window_clean_future() {
  564. let mut window = MovingWindow::new(NanoTimestamp::from_secs(60));
  565. let future = UNIX_EPOCH.elapsed().unwrap().as_secs() + 100;
  566. window.times.push_back(NanoTimestamp::from_secs(future.into()));
  567. window.clean();
  568. assert_eq!(window.count(), 0);
  569. }
  570. }