1use std::{
5 collections::HashMap,
6 future::Future,
7 marker::PhantomData,
8 sync::{
9 Arc,
10 atomic::{AtomicU64, Ordering},
11 },
12 time::{Duration, Instant},
13};
14
15use anyhow::{Context, Result, anyhow};
16use data_source::DataSource;
17use derive_more::derive::Deref;
18use hotshot_types::traits::signature_key::SignatureKey;
19use message::{Message, MessageFrame, RequestMessage, ResponseMessage};
20use network::{Bytes, Receiver, Sender};
21use parking_lot::RwLock;
22use rand::seq::SliceRandom;
23use recipient_source::RecipientSource;
24use request::Request;
25use tokio::{
26 spawn,
27 sync::mpsc,
28 time::{sleep, timeout},
29};
30use tokio_util::task::AbortOnDropHandle;
31use tracing::{debug, error, info, trace, warn};
32use util::{BoundedVecDeque, NamedSemaphore, NamedSemaphoreError};
33
34pub mod data_source;
36pub mod message;
38pub mod network;
41pub mod recipient_source;
44pub mod request;
46mod util;
48
49pub type RequestHash = blake3::Hash;
51
52type ActiveRequestsMap = Arc<RwLock<HashMap<RequestHash, Vec<Waiter>>>>;
56
57pub type IncomingRequests<K> = NamedSemaphore<K>;
59
60const RESPONSE_BUFFER_SIZE: usize = 16;
65
66#[derive(thiserror::Error, Debug)]
68pub enum RequestError {
69 #[error("request timed out")]
71 Timeout,
72 #[error("request was invalid")]
74 InvalidRequest(anyhow::Error),
75 #[error("other error")]
77 Other(anyhow::Error),
78}
79
80pub trait Serializable: Sized {
83 fn to_bytes(&self) -> Result<Vec<u8>>;
90
91 fn from_bytes(bytes: &[u8]) -> Result<Self>;
96}
97
98#[derive(Clone)]
100pub struct RequestResponseConfig {
101 pub incoming_request_ttl: Duration,
104 pub incoming_request_timeout: Duration,
107 pub request_batch_size: usize,
110 pub request_batch_interval: Duration,
112 pub max_incoming_requests: usize,
114 pub max_incoming_requests_per_key: usize,
116}
117
118#[derive(Deref)]
121pub struct RequestResponse<
122 S: Sender<K>,
123 R: Receiver,
124 Req: Request,
125 RS: RecipientSource<Req, K>,
126 DS: DataSource<Req>,
127 K: SignatureKey + 'static,
128> {
129 #[deref]
130 pub inner: Arc<RequestResponseInner<S, R, Req, RS, DS, K>>,
132 _receiving_task_handle: Arc<AbortOnDropHandle<()>>,
134}
135
136impl<
139 S: Sender<K>,
140 R: Receiver,
141 Req: Request,
142 RS: RecipientSource<Req, K>,
143 DS: DataSource<Req>,
144 K: SignatureKey + 'static,
145> Clone for RequestResponse<S, R, Req, RS, DS, K>
146{
147 fn clone(&self) -> Self {
148 Self {
149 inner: Arc::clone(&self.inner),
150 _receiving_task_handle: Arc::clone(&self._receiving_task_handle),
151 }
152 }
153}
154
155impl<
156 S: Sender<K>,
157 R: Receiver,
158 Req: Request,
159 RS: RecipientSource<Req, K>,
160 DS: DataSource<Req>,
161 K: SignatureKey + 'static,
162> RequestResponse<S, R, Req, RS, DS, K>
163{
164 pub fn new(
166 config: RequestResponseConfig,
168 sender: S,
170 receiver: R,
172 recipient_source: RS,
175 data_source: DS,
178 ) -> Self {
179 let inner = Arc::new(RequestResponseInner {
181 config,
182 sender,
183 recipient_source,
184 data_source,
185 active_requests: ActiveRequestsMap::default(),
186 next_waiter_id: AtomicU64::new(0),
187 phantom_data: PhantomData,
188 });
189
190 let inner_clone = Arc::clone(&inner);
193 let receive_task_handle =
194 AbortOnDropHandle::new(tokio::spawn(inner_clone.receiving_task(receiver)));
195
196 Self {
198 inner,
199 _receiving_task_handle: Arc::new(receive_task_handle),
200 }
201 }
202}
203
204pub struct RequestResponseInner<
206 S: Sender<K>,
207 R: Receiver,
208 Req: Request,
209 RS: RecipientSource<Req, K>,
210 DS: DataSource<Req>,
211 K: SignatureKey + 'static,
212> {
213 config: RequestResponseConfig,
215 pub sender: S,
217 pub recipient_source: RS,
219 data_source: DS,
221 active_requests: ActiveRequestsMap,
223 next_waiter_id: AtomicU64,
225 phantom_data: PhantomData<(K, R, Req, DS)>,
227}
228impl<
229 S: Sender<K>,
230 R: Receiver,
231 Req: Request,
232 RS: RecipientSource<Req, K>,
233 DS: DataSource<Req>,
234 K: SignatureKey + 'static,
235> RequestResponseInner<S, R, Req, RS, DS, K>
236{
237 pub async fn request_indefinitely<F, Fut, O>(
244 self: &Arc<Self>,
245 public_key: &K,
246 private_key: &K::PrivateKey,
247 estimated_request_ttl: Duration,
250 request: Req,
252 response_validation_fn: F,
254 ) -> std::result::Result<O, RequestError>
255 where
256 F: Fn(&Req, Req::Response) -> Fut + Send + Sync + Clone,
257 Fut: Future<Output = anyhow::Result<O>> + Send,
258 O: Send,
259 {
260 loop {
261 let request_message = RequestMessage::new_signed(public_key, private_key, &request)
263 .map_err(|e| {
264 RequestError::InvalidRequest(anyhow::anyhow!(
265 "failed to sign request message: {e}"
266 ))
267 })?;
268
269 match self
271 .request(
272 request_message,
273 estimated_request_ttl,
274 response_validation_fn.clone(),
275 )
276 .await
277 {
278 Ok(response) => return Ok(response),
279 Err(RequestError::Timeout) => continue,
280 Err(e) => return Err(e),
281 }
282 }
283 }
284
285 pub async fn request<F, Fut, O>(
294 self: &Arc<Self>,
295 request_message: RequestMessage<Req, K>,
296 timeout_duration: Duration,
297 response_validation_fn: F,
298 ) -> std::result::Result<O, RequestError>
299 where
300 F: Fn(&Req, Req::Response) -> Fut + Send + Sync,
301 Fut: Future<Output = anyhow::Result<O>> + Send,
302 O: Send,
303 {
304 let request_hash = blake3::hash(&request_message.request.to_bytes().map_err(|e| {
306 RequestError::InvalidRequest(anyhow::anyhow!(
307 "failed to serialize request message: {e}"
308 ))
309 })?);
310
311 let mut response_receiver = self.register_waiter(request_hash);
314
315 let message = Bytes::from(
316 Message::Request(request_message.clone())
317 .to_bytes()
318 .map_err(|e| {
319 RequestError::InvalidRequest(anyhow::anyhow!(
320 "failed to serialize request message: {e}"
321 ))
322 })?,
323 );
324
325 timeout(timeout_duration, async {
327 let _batched_sending_task = self
330 .spawn_batched_sender(request_message.clone(), message, timeout_duration)
331 .await?;
332
333 loop {
334 let body = response_receiver.recv().await.ok_or_else(|| {
335 RequestError::Other(anyhow!("response channel closed"))
338 })?;
339
340 let response = match Req::Response::from_bytes(&body) {
344 Ok(response) => response,
345 Err(e) => {
346 debug!("Received undecodable response: {e:#}");
347 continue;
348 },
349 };
350
351 match response_validation_fn(&request_message.request, response).await {
352 Ok(validated) => return Ok(validated),
353 Err(e) => debug!("Received invalid response: {e:#}"),
354 }
355 }
356 })
357 .await
358 .map_err(|_| RequestError::Timeout)?
359 }
360
361 fn register_waiter(self: &Arc<Self>, request_hash: RequestHash) -> ResponseReceiver {
363 let (sender, receiver) = mpsc::channel(RESPONSE_BUFFER_SIZE);
364 let id = self.next_waiter_id.fetch_add(1, Ordering::Relaxed);
365
366 self.active_requests
367 .write()
368 .entry(request_hash)
369 .or_default()
370 .push(Waiter { id, sender });
371
372 ResponseReceiver {
373 request_hash,
374 id,
375 receiver,
376 active_requests: Arc::clone(&self.active_requests),
377 }
378 }
379
380 async fn spawn_batched_sender(
384 self: &Arc<Self>,
385 request_message: RequestMessage<Req, K>,
386 message: Bytes,
387 timeout_duration: Duration,
388 ) -> std::result::Result<AbortOnDropHandle<()>, RequestError> {
389 let mut recipients = self
391 .recipient_source
392 .get_expected_responders(&request_message.request)
393 .await
394 .map_err(|e| {
395 RequestError::InvalidRequest(anyhow::anyhow!(
396 "failed to get expected responders for request: {e}"
397 ))
398 })?;
399 recipients.shuffle(&mut rand::thread_rng());
400
401 let start_time = Instant::now();
402
403 let self_clone = Arc::clone(self);
404 Ok(AbortOnDropHandle::new(spawn(async move {
405 if recipients.is_empty() {
408 debug!("No recipients for request {request_message:?}");
409 return;
410 }
411
412 let mut outgoing_requests = BoundedVecDeque::new(self_clone.config.request_batch_size);
415
416 while start_time.elapsed() < timeout_duration {
417 for recipient_batch in recipients.chunks(self_clone.config.request_batch_size) {
418 for recipient in recipient_batch {
419 let self_clone = Arc::clone(&self_clone);
420 let request_message_clone = request_message.clone();
421 let recipient_clone = recipient.clone();
422 let message_clone = Arc::clone(&message);
423
424 let individual_sending_task = spawn(async move {
425 trace!(
426 "Sending request {request_message_clone:?} to {recipient_clone:?}"
427 );
428
429 let _ = self_clone
430 .sender
431 .send_direct_message(&message_clone, recipient_clone)
432 .await;
433 });
434
435 outgoing_requests.push(AbortOnDropHandle::new(individual_sending_task));
436 }
437
438 sleep(self_clone.config.request_batch_interval).await;
439 }
440 }
441 })))
442 }
443
444 async fn receiving_task(self: Arc<Self>, mut receiver: R) {
446 let mut incoming_requests = NamedSemaphore::new(
448 self.config.max_incoming_requests_per_key,
449 Some(self.config.max_incoming_requests),
450 );
451
452 loop {
453 match receiver.receive_message().await {
454 Ok(message) => {
455 if let Err(e) = self.handle_message(&message, &mut incoming_requests) {
456 warn!("Received invalid message: {e:#}");
457 }
458 },
459 Err(e) => {
461 error!("Request/response receive task exited: {e:#}");
462 return;
463 },
464 }
465 }
466 }
467
468 fn handle_message(
470 self: &Arc<Self>,
471 message: &[u8],
472 incoming_requests: &mut IncomingRequests<K>,
473 ) -> Result<()> {
474 match MessageFrame::parse(message)? {
475 MessageFrame::Request { body } => {
476 self.handle_request(RequestMessage::from_bytes(body)?, incoming_requests);
477 },
478 MessageFrame::Response { request_hash, body } => {
479 self.handle_response(request_hash, body);
480 },
481 }
482 Ok(())
483 }
484
485 fn handle_request(
487 self: &Arc<Self>,
488 request_message: RequestMessage<Req, K>,
489 incoming_requests: &mut IncomingRequests<K>,
490 ) {
491 trace!("Handling request {:?}", request_message);
492
493 let self_clone = Arc::clone(self);
498
499 let permit = incoming_requests.try_acquire(request_message.public_key.clone());
502 match permit {
503 Ok(ref permit) => permit,
504 Err(NamedSemaphoreError::PerKeyLimitReached) => {
505 info!(
506 "Failed to process request from {}: too many requests from the same key are \
507 already being processed",
508 request_message.public_key
509 );
510 return;
511 },
512 Err(NamedSemaphoreError::GlobalLimitReached) => {
513 info!(
514 "Failed to process request from {}: too many requests are already being \
515 processed",
516 request_message.public_key
517 );
518 return;
519 },
520 };
521
522 tokio::spawn(async move {
523 let result = timeout(self_clone.config.incoming_request_timeout, async move {
524 request_message
529 .validate(self_clone.config.incoming_request_ttl)
530 .with_context(|| "failed to validate request")?;
531
532 let response = self_clone
534 .data_source
535 .derive_response_for(&request_message.request)
536 .await
537 .with_context(|| "failed to derive response for request")?;
538
539 let response = Bytes::from(
541 Message::Response::<Req, K>(ResponseMessage {
542 request_hash: blake3::hash(&request_message.request.to_bytes()?),
543 response,
544 })
545 .to_bytes()
546 .with_context(|| "failed to serialize response message")?,
547 );
548
549 self_clone
551 .sender
552 .send_direct_message(&response, request_message.public_key)
553 .await
554 .with_context(|| "failed to send response to requester")?;
555
556 _ = permit;
558 drop(permit);
559
560 Ok::<(), anyhow::Error>(())
561 })
562 .await
563 .map_err(|_| anyhow::anyhow!("timed out while sending response"))
564 .and_then(|result| result);
565
566 if let Err(e) = result {
567 debug!("Failed to send response to requester: {e:#}");
568 }
569 });
570 }
571
572 fn handle_response(&self, request_hash: RequestHash, body: &[u8]) {
576 trace!("Handling response for request {request_hash}");
577
578 let waiters: Vec<mpsc::Sender<Bytes>> = {
580 let active_requests = self.active_requests.read();
581 let Some(waiters) = active_requests.get(&request_hash) else {
582 trace!("Received response for inactive request {request_hash}");
584 return;
585 };
586 waiters.iter().map(|waiter| waiter.sender.clone()).collect()
587 };
588
589 let body = Bytes::from(body.to_vec());
593 for waiter in waiters {
594 if let Err(mpsc::error::TrySendError::Full(_)) = waiter.try_send(Arc::clone(&body)) {
595 debug!("Dropped response for request {request_hash}: waiter buffer full");
596 }
597 }
598 }
599}
600
601struct Waiter {
604 id: u64,
606 sender: mpsc::Sender<Bytes>,
609}
610
611struct ResponseReceiver {
615 request_hash: RequestHash,
617 id: u64,
619 receiver: mpsc::Receiver<Bytes>,
621 active_requests: ActiveRequestsMap,
623}
624
625impl ResponseReceiver {
626 async fn recv(&mut self) -> Option<Bytes> {
627 self.receiver.recv().await
628 }
629}
630
631impl Drop for ResponseReceiver {
632 fn drop(&mut self) {
633 let mut active_requests = self.active_requests.write();
634 if let Some(waiters) = active_requests.get_mut(&self.request_hash) {
635 waiters.retain(|waiter| waiter.id != self.id);
636 if waiters.is_empty() {
637 active_requests.remove(&self.request_hash);
638 }
639 }
640 }
641}
642
643#[cfg(test)]
644mod tests {
645 use std::{
646 collections::HashMap,
647 sync::{
648 Mutex,
649 atomic::{AtomicBool, AtomicUsize},
650 },
651 };
652
653 use async_trait::async_trait;
654 use hotshot_types::signature_key::{BLSPrivKey, BLSPubKey};
655 use rand::Rng;
656 use tokio::{sync::mpsc, task::JoinSet};
657
658 use super::*;
659
660 #[derive(Clone)]
662 pub struct TestSender {
663 network: Arc<HashMap<BLSPubKey, mpsc::Sender<Bytes>>>,
664 }
665
666 #[async_trait]
668 impl Sender<BLSPubKey> for TestSender {
669 async fn send_direct_message(&self, message: &Bytes, recipient: BLSPubKey) -> Result<()> {
670 self.network
671 .get(&recipient)
672 .ok_or(anyhow::anyhow!("recipient not found"))?
673 .send(Arc::clone(message))
674 .await
675 .map_err(|_| anyhow::anyhow!("failed to send message"))?;
676
677 Ok(())
678 }
679 }
680
681 #[async_trait]
683 impl RecipientSource<TestRequest, BLSPubKey> for TestSender {
684 async fn get_expected_responders(&self, _request: &TestRequest) -> Result<Vec<BLSPubKey>> {
685 Ok(self.network.keys().copied().collect())
687 }
688 }
689
690 #[derive(Clone, Debug)]
692 struct TestRequest(Vec<u8>);
693
694 impl Serializable for TestRequest {
696 fn to_bytes(&self) -> Result<Vec<u8>> {
697 Ok(self.0.clone())
698 }
699
700 fn from_bytes(bytes: &[u8]) -> Result<Self> {
701 Ok(TestRequest(bytes.to_vec()))
702 }
703 }
704
705 impl Request for TestRequest {
707 type Response = Vec<u8>;
708 fn validate(&self) -> Result<()> {
709 Ok(())
710 }
711 }
712
713 #[derive(Clone)]
715 struct TestDataSource {
716 has_data: bool,
718 data_available_time: Instant,
720
721 take_data: bool,
723 taken: Arc<AtomicBool>,
725 }
726
727 #[async_trait]
728 impl DataSource<TestRequest> for TestDataSource {
729 async fn derive_response_for(&self, request: &TestRequest) -> Result<Vec<u8>> {
730 if self.has_data && Instant::now() >= self.data_available_time {
732 if self.take_data && !self.taken.swap(true, std::sync::atomic::Ordering::Relaxed) {
733 return Err(anyhow::anyhow!("data already taken"));
734 }
735 Ok(blake3::hash(&request.0).as_bytes().to_vec())
736 } else {
737 Err(anyhow::anyhow!("did not have the data"))
738 }
739 }
740 }
741
742 fn default_protocol_config() -> RequestResponseConfig {
744 RequestResponseConfig {
745 incoming_request_ttl: Duration::from_secs(40),
746 incoming_request_timeout: Duration::from_secs(40),
747 request_batch_size: 10,
748 request_batch_interval: Duration::from_millis(100),
749 max_incoming_requests: 10,
750 max_incoming_requests_per_key: 1,
751 }
752 }
753
754 fn create_participants(
756 num: usize,
757 ) -> Vec<(TestSender, mpsc::Receiver<Bytes>, (BLSPubKey, BLSPrivKey))> {
758 let mut network = HashMap::new();
760
761 let mut receivers = Vec::new();
763
764 let mut keypairs = Vec::new();
766
767 for i in 0..num {
769 let (public_key, private_key) =
771 BLSPubKey::generated_from_seed_indexed([2; 32], i.try_into().unwrap());
772
773 keypairs.push((public_key, private_key));
775
776 let (sender, receiver) = mpsc::channel::<Bytes>(100);
778
779 network.insert(public_key, sender);
781
782 receivers.push(receiver);
784 }
785
786 let sender = TestSender {
788 network: Arc::new(network),
789 };
790
791 receivers
793 .into_iter()
794 .zip(keypairs)
795 .map(|(r, k)| (sender.clone(), r, k))
796 .collect()
797 }
798
799 #[derive(Clone)]
801 struct IntegrationTestConfig {
802 request_response_config: RequestResponseConfig,
804 num_participants: usize,
806 num_participants_with_data: usize,
808 request_timeout: Duration,
810 data_available_delay: Duration,
812 }
813
814 struct IntegrationTestResult {
816 num_succeeded: usize,
818 }
819
820 async fn run_integration_test(config: IntegrationTestConfig) -> IntegrationTestResult {
822 let participants = create_participants(config.num_participants);
824
825 let mut join_set = JoinSet::new();
827
828 let handles = Arc::new(Mutex::new(Vec::new()));
830
831 for (i, (sender, receiver, (public_key, private_key))) in
833 participants.into_iter().enumerate()
834 {
835 let config_clone = config.request_response_config.clone();
836 let handles_clone = Arc::clone(&handles);
837 join_set.spawn(async move {
838 let protocol = RequestResponse::new(
839 config_clone,
840 sender.clone(),
841 receiver,
842 sender,
843 TestDataSource {
844 has_data: i < config.num_participants_with_data,
845 data_available_time: Instant::now() + config.data_available_delay,
846 take_data: false,
847 taken: Arc::new(AtomicBool::new(false)),
848 },
849 );
850
851 #[allow(clippy::used_underscore_binding)]
854 handles_clone
855 .lock()
856 .unwrap()
857 .push(Arc::clone(&protocol._receiving_task_handle));
858
859 let request = TestRequest(vec![rand::thread_rng().r#gen(); 100]);
861
862 let request_hash = blake3::hash(&request.0).as_bytes().to_vec();
864
865 let request = RequestMessage::new_signed(&public_key, &private_key, &request)
867 .expect("failed to create request message");
868
869 let response = protocol
871 .request(
872 request,
873 config.request_timeout,
874 |_request, response| async move { Ok(response) },
875 )
876 .await?;
877
878 assert_eq!(response, request_hash);
880
881 Ok::<(), anyhow::Error>(())
882 });
883 }
884
885 let mut num_succeeded = config.num_participants;
887 while let Some(result) = join_set.join_next().await {
888 if result.is_err() || result.unwrap().is_err() {
889 num_succeeded -= 1;
890 }
891 }
892
893 IntegrationTestResult { num_succeeded }
894 }
895
896 #[tokio::test(flavor = "multi_thread")]
898 async fn test_integration_50_0s() {
899 let config = IntegrationTestConfig {
901 request_response_config: default_protocol_config(),
902 num_participants: 100,
903 num_participants_with_data: 50,
904 request_timeout: Duration::from_secs(40),
905 data_available_delay: Duration::from_secs(0),
906 };
907
908 let result = run_integration_test(config).await;
910 assert_eq!(result.num_succeeded, 100);
911 }
912
913 #[tokio::test(flavor = "multi_thread")]
916 async fn test_integration_0() {
917 let config = IntegrationTestConfig {
919 request_response_config: default_protocol_config(),
920 num_participants: 100,
921 num_participants_with_data: 0,
922 request_timeout: Duration::from_secs(40),
923 data_available_delay: Duration::from_secs(0),
924 };
925
926 let result = run_integration_test(config).await;
928
929 assert_eq!(result.num_succeeded, 0);
931 }
932
933 #[tokio::test(flavor = "multi_thread")]
936 async fn test_integration_1_1s() {
937 let config = IntegrationTestConfig {
939 request_response_config: default_protocol_config(),
940 num_participants: 100,
941 num_participants_with_data: 1,
942 request_timeout: Duration::from_secs(40),
943 data_available_delay: Duration::from_secs(2),
944 };
945
946 let result = run_integration_test(config).await;
948
949 assert_eq!(result.num_succeeded, 100);
951 }
952
953 #[tokio::test(flavor = "multi_thread")]
955 async fn test_join_existing_request() {
956 let config = default_protocol_config();
958
959 let mut participants = Vec::new();
961
962 for (sender, receiver, (public_key, private_key)) in create_participants(2) {
963 let protocol = RequestResponse::new(
965 config.clone(),
966 sender.clone(),
967 receiver,
968 sender,
969 TestDataSource {
970 take_data: true,
971 has_data: true,
972 data_available_time: Instant::now() + Duration::from_secs(2),
973 taken: Arc::new(AtomicBool::new(false)),
974 },
975 );
976
977 participants.push((protocol, public_key, private_key));
979 }
980
981 let one = Arc::new(participants.remove(0));
983
984 let request = TestRequest(vec![rand::thread_rng().r#gen(); 100]);
986
987 let mut join_set = JoinSet::new();
989
990 for _ in 0..10 {
992 let one_clone = Arc::clone(&one);
994
995 let request_clone = request.clone();
997
998 join_set.spawn(async move {
1000 let request_message =
1002 RequestMessage::new_signed(&one_clone.1, &one_clone.2, &request_clone)?;
1003
1004 one_clone
1006 .0
1007 .request(
1008 request_message,
1009 Duration::from_secs(20),
1010 |_request, response| async move { Ok(response) },
1011 )
1012 .await?;
1013
1014 Ok::<(), anyhow::Error>(())
1015 });
1016 }
1017
1018 while let Some(result) = join_set.join_next().await {
1020 result
1021 .expect("failed to join task")
1022 .expect("failed to request data");
1023 }
1024 }
1025
1026 type TestProtocol = RequestResponse<
1028 TestSender,
1029 mpsc::Receiver<Bytes>,
1030 TestRequest,
1031 TestSender,
1032 TestDataSource,
1033 BLSPubKey,
1034 >;
1035
1036 fn create_protocols(
1038 num: usize,
1039 has_data: bool,
1040 ) -> Vec<(TestProtocol, (BLSPubKey, BLSPrivKey))> {
1041 create_participants(num)
1042 .into_iter()
1043 .map(|(sender, receiver, keypair)| {
1044 let protocol = RequestResponse::new(
1045 default_protocol_config(),
1046 sender.clone(),
1047 receiver,
1048 sender,
1049 TestDataSource {
1050 has_data,
1051 data_available_time: Instant::now(),
1052 take_data: false,
1053 taken: Arc::new(AtomicBool::new(false)),
1054 },
1055 );
1056 (protocol, keypair)
1057 })
1058 .collect()
1059 }
1060
1061 struct StalledRecipientSource;
1063
1064 #[async_trait]
1065 impl RecipientSource<TestRequest, BLSPubKey> for StalledRecipientSource {
1066 async fn get_expected_responders(&self, _request: &TestRequest) -> Result<Vec<BLSPubKey>> {
1067 std::future::pending().await
1068 }
1069 }
1070
1071 #[tokio::test(flavor = "multi_thread")]
1073 async fn test_timeout_covers_sending() {
1074 let (sender, receiver, (public_key, private_key)) = create_participants(1).remove(0);
1075 let protocol = RequestResponse::new(
1076 default_protocol_config(),
1077 sender,
1078 receiver,
1079 StalledRecipientSource,
1080 TestDataSource {
1081 has_data: false,
1082 data_available_time: Instant::now(),
1083 take_data: false,
1084 taken: Arc::new(AtomicBool::new(false)),
1085 },
1086 );
1087
1088 let request_message =
1089 RequestMessage::new_signed(&public_key, &private_key, &TestRequest(vec![1, 2, 3]))
1090 .expect("failed to create request message");
1091
1092 let result = timeout(
1093 Duration::from_secs(5),
1094 protocol.request(
1095 request_message,
1096 Duration::from_millis(250),
1097 |_request, response| async move { Ok(response) },
1098 ),
1099 )
1100 .await
1101 .expect("request outlived its own timeout");
1102 assert!(matches!(result, Err(RequestError::Timeout)));
1103 }
1104
1105 #[tokio::test(flavor = "multi_thread")]
1107 async fn test_waiter_cleanup_on_timeout() {
1108 let mut protocols = create_protocols(2, false);
1110 let (protocol, (public_key, private_key)) = protocols.remove(0);
1111
1112 let request_message =
1113 RequestMessage::new_signed(&public_key, &private_key, &TestRequest(vec![1, 2, 3]))
1114 .expect("failed to create request message");
1115
1116 let result = protocol
1117 .request(
1118 request_message,
1119 Duration::from_millis(250),
1120 |_request, response| async move { Ok(response) },
1121 )
1122 .await;
1123 assert!(matches!(result, Err(RequestError::Timeout)));
1124
1125 assert!(protocol.active_requests.read().is_empty());
1127 }
1128
1129 #[tokio::test(flavor = "multi_thread")]
1133 async fn test_join_with_different_output_types() {
1134 let protocols = create_protocols(2, true);
1135 let (requester, (public_key, private_key)) = &protocols[0];
1136
1137 let request = TestRequest(vec![5; 100]);
1138 let expected = blake3::hash(&request.0).as_bytes().to_vec();
1139
1140 let request_message_1 = RequestMessage::new_signed(public_key, private_key, &request)
1141 .expect("failed to create request message");
1142 let request_message_2 = RequestMessage::new_signed(public_key, private_key, &request)
1143 .expect("failed to create request message");
1144
1145 let (bytes, length) = tokio::join!(
1147 requester.request(
1148 request_message_1,
1149 Duration::from_secs(20),
1150 |_request, response| async move { Ok(response) },
1151 ),
1152 requester.request(
1153 request_message_2,
1154 Duration::from_secs(20),
1155 |_request, response| async move { Ok(response.len()) },
1156 )
1157 );
1158
1159 assert_eq!(bytes.expect("bytes request failed"), expected);
1160 assert_eq!(length.expect("length request failed"), expected.len());
1161 }
1162
1163 #[tokio::test(flavor = "multi_thread")]
1165 async fn test_invalid_then_valid_response() {
1166 let protocols = create_protocols(2, true);
1167 let (requester, (public_key, private_key)) = &protocols[0];
1168
1169 let attempts = Arc::new(AtomicUsize::new(0));
1171 let attempts_clone = Arc::clone(&attempts);
1172 let validation_fn = move |_request: &TestRequest, response: Vec<u8>| {
1173 let attempts = Arc::clone(&attempts_clone);
1174 async move {
1175 if attempts.fetch_add(1, std::sync::atomic::Ordering::SeqCst) == 0 {
1176 return Err(anyhow::anyhow!("rejecting the first response"));
1177 }
1178 Ok(response)
1179 }
1180 };
1181
1182 let request = TestRequest(vec![7; 100]);
1183 let request_message = RequestMessage::new_signed(public_key, private_key, &request)
1184 .expect("failed to create request message");
1185 let response = requester
1186 .request(request_message, Duration::from_secs(20), validation_fn)
1187 .await
1188 .expect("request failed");
1189
1190 assert_eq!(response, blake3::hash(&request.0).as_bytes().to_vec());
1191 assert!(attempts.load(std::sync::atomic::Ordering::SeqCst) >= 2);
1192
1193 assert!(requester.active_requests.read().is_empty());
1195 }
1196
1197 #[tokio::test(flavor = "multi_thread")]
1200 async fn test_malformed_messages_are_ignored() {
1201 let protocols = create_protocols(2, true);
1202 let (requester, (public_key, private_key)) = &protocols[0];
1203 let inbox = requester
1204 .sender
1205 .network
1206 .get(public_key)
1207 .expect("requester has an inbox");
1208
1209 let mut unknown_response = vec![1];
1212 unknown_response.extend_from_slice(blake3::hash(b"nobody asked").as_bytes());
1213 unknown_response.extend_from_slice(b"payload");
1214 for junk in [vec![], vec![7], vec![1; 20], unknown_response] {
1215 inbox
1216 .send(Bytes::from(junk))
1217 .await
1218 .expect("failed to inject");
1219 }
1220
1221 let request = TestRequest(vec![11; 100]);
1222 let request_message = RequestMessage::new_signed(public_key, private_key, &request)
1223 .expect("failed to create request message");
1224 let response = requester
1225 .request(
1226 request_message,
1227 Duration::from_secs(20),
1228 |_request, response| async move { Ok(response) },
1229 )
1230 .await
1231 .expect("request failed");
1232
1233 assert_eq!(response, blake3::hash(&request.0).as_bytes().to_vec());
1234 assert!(requester.active_requests.read().is_empty());
1235 }
1236}