Skip to main content

rings_node/
processor.rs

1#![warn(missing_docs)]
2
3//! Processor of rings-node rpc server.
4
5use std::str::FromStr;
6use std::sync::Arc;
7use std::time::Duration;
8
9use rings_core::chunk::ReassemblyLimits;
10use rings_core::dht::Did;
11use rings_core::dht::EntryStorage;
12use rings_core::dht::DEFAULT_FINGER_TABLE_SIZE;
13use rings_core::ecc::PublicKey;
14use rings_core::ecc::SecretKey;
15use rings_core::measure::MeasureImpl;
16use rings_core::message::e2e;
17use rings_core::message::e2e::E2eHandshakeRequest;
18use rings_core::message::e2e::E2eHandshakeResponse;
19use rings_core::message::e2e::E2eStreamDecryptor;
20use rings_core::message::e2e::E2eStreamFrame;
21use rings_core::message::Encoded;
22use rings_core::message::Encoder;
23use rings_core::message::Message;
24use rings_core::prelude::uuid;
25use rings_core::storage::MemStorage;
26use rings_core::swarm::Swarm;
27use rings_core::swarm::SwarmBuilder;
28use rings_rpc::protos::rings_node::*;
29use serde::Deserialize;
30use serde::Serialize;
31
32use crate::consts::DATA_REDUNDANT;
33use crate::error::Error;
34use crate::error::Result;
35use crate::measure::PeriodicMeasure;
36use crate::prelude::entry;
37use crate::prelude::wasm_export;
38use crate::prelude::ChordStorageInterface;
39use crate::prelude::ChordStorageInterfaceCacheChecker;
40use crate::prelude::SessionSk;
41
42/// ProcessorConfig is usually serialized as json or yaml.
43/// There is a `from_config` method in [ProcessorBuilder] used to initialize the Builder with a serialized ProcessorConfig.
44#[derive(Clone, Debug)]
45#[wasm_export]
46pub struct ProcessorConfig {
47    /// The network_id is used to distinguish different networks.
48    /// Use 1 for main network.
49    network_id: u32,
50    /// ICE servers for webrtc
51    ice_servers: String,
52    /// External address for webrtc
53    external_address: Option<String>,
54    /// [SessionSk].
55    session_sk: SessionSk,
56    /// Stabilization interval.
57    stabilize_interval: Duration,
58}
59
60#[wasm_export]
61impl ProcessorConfig {
62    /// Creates a new `ProcessorConfig` instance without an external address.
63    pub fn new(
64        network_id: u32,
65        ice_servers: String,
66        session_sk: SessionSk,
67        stabilize_interval: u64,
68    ) -> Self {
69        Self {
70            network_id,
71            ice_servers,
72            external_address: None,
73            session_sk,
74            stabilize_interval: Duration::from_secs(stabilize_interval),
75        }
76    }
77
78    /// Return associated [SessionSk].
79    pub fn session_sk(&self) -> SessionSk {
80        self.session_sk.clone()
81    }
82}
83
84impl FromStr for ProcessorConfig {
85    type Err = Error;
86    /// Reveal config from serialized string.
87    fn from_str(ser: &str) -> Result<Self> {
88        serde_yaml::from_str::<ProcessorConfig>(ser).map_err(Error::SerdeYamlError)
89    }
90}
91
92/// `ProcessorConfigSerialized` is a serialized version of `ProcessorConfig`.
93/// Instead of storing the `SessionSk` instance, it stores the dumped string representation of the session secret key.
94#[derive(Serialize, Deserialize, Clone)]
95#[wasm_export]
96pub struct ProcessorConfigSerialized {
97    /// The network_id is used to distinguish different networks.
98    /// Use 1 for main network.
99    network_id: u32,
100    /// A string representing ICE servers for WebRTC
101    ice_servers: String,
102    /// An optional string representing the external address for WebRTC
103    external_address: Option<String>,
104    /// A string representing the dumped `SessionSk`.
105    session_sk: String,
106    /// An unsigned integer representing the stabilization interval in seconds.
107    stabilize_interval: u64,
108}
109
110impl ProcessorConfigSerialized {
111    /// Creates a new `ProcessorConfigSerialized` instance without an external address.
112    pub fn new(
113        network_id: u32,
114        ice_servers: String,
115        session_sk: String,
116        stabilize_interval: u64,
117    ) -> Self {
118        Self {
119            network_id,
120            ice_servers,
121            external_address: None,
122            session_sk,
123            stabilize_interval,
124        }
125    }
126
127    /// Sets up the external address for WebRTC.
128    /// This will be used to configure the transport to listen for WebRTC connections in "HOST" mode.
129    pub fn external_address(mut self, external_address: String) -> Self {
130        self.external_address = Some(external_address);
131        self
132    }
133}
134
135impl TryFrom<ProcessorConfig> for ProcessorConfigSerialized {
136    type Error = Error;
137    fn try_from(ins: ProcessorConfig) -> Result<Self> {
138        Ok(Self {
139            network_id: ins.network_id,
140            ice_servers: ins.ice_servers.clone(),
141            external_address: ins.external_address.clone(),
142            session_sk: ins.session_sk.dump()?,
143            stabilize_interval: ins.stabilize_interval.as_secs(),
144        })
145    }
146}
147
148impl TryFrom<ProcessorConfigSerialized> for ProcessorConfig {
149    type Error = Error;
150    fn try_from(ins: ProcessorConfigSerialized) -> Result<Self> {
151        Ok(Self {
152            network_id: ins.network_id,
153            ice_servers: ins.ice_servers.clone(),
154            external_address: ins.external_address.clone(),
155            session_sk: SessionSk::from_str(&ins.session_sk)?,
156            stabilize_interval: Duration::from_secs(ins.stabilize_interval),
157        })
158    }
159}
160
161impl Serialize for ProcessorConfig {
162    fn serialize<S: serde::Serializer>(
163        &self,
164        serializer: S,
165    ) -> core::result::Result<S::Ok, S::Error> {
166        let ins: ProcessorConfigSerialized = self
167            .clone()
168            .try_into()
169            .map_err(|e: Error| serde::ser::Error::custom(e.to_string()))?;
170        ProcessorConfigSerialized::serialize(&ins, serializer)
171    }
172}
173
174impl<'de> serde::de::Deserialize<'de> for ProcessorConfig {
175    fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error>
176    where D: serde::Deserializer<'de> {
177        match ProcessorConfigSerialized::deserialize(deserializer) {
178            Ok(ins) => {
179                let cfg: ProcessorConfig = ins
180                    .try_into()
181                    .map_err(|e: Error| serde::de::Error::custom(e.to_string()))?;
182                Ok(cfg)
183            }
184            Err(e) => Err(e),
185        }
186    }
187}
188
189/// ProcessorBuilder is used to initialize a [Processor] instance.
190pub struct ProcessorBuilder {
191    network_id: u32,
192    ice_servers: String,
193    external_address: Option<String>,
194    session_sk: SessionSk,
195    storage: Option<EntryStorage>,
196    measure: Option<MeasureImpl>,
197    stabilize_interval: Duration,
198    dht_finger_table_size: usize,
199    reassembly_limits: ReassemblyLimits,
200}
201
202/// Processor for rings-node rpc server
203#[derive(Clone)]
204pub struct Processor {
205    /// a swarm instance
206    pub swarm: Arc<Swarm>,
207    stabilize_interval: Duration,
208}
209
210impl ProcessorBuilder {
211    /// initialize a [ProcessorBuilder] with a serialized [ProcessorConfig].
212    pub fn from_serialized(config: &str) -> Result<Self> {
213        let config =
214            serde_yaml::from_str::<ProcessorConfig>(config).map_err(Error::SerdeYamlError)?;
215        Self::from_config(&config)
216    }
217
218    /// initialize a [ProcessorBuilder] with a [ProcessorConfig].
219    pub fn from_config(config: &ProcessorConfig) -> Result<Self> {
220        Ok(Self {
221            network_id: config.network_id,
222            ice_servers: config.ice_servers.clone(),
223            external_address: config.external_address.clone(),
224            session_sk: config.session_sk.clone(),
225            storage: None,
226            measure: None,
227            stabilize_interval: config.stabilize_interval,
228            dht_finger_table_size: DEFAULT_FINGER_TABLE_SIZE,
229            reassembly_limits: ReassemblyLimits::production(),
230        })
231    }
232
233    /// Set the storage for the processor.
234    pub fn storage(mut self, storage: EntryStorage) -> Self {
235        self.storage = Some(storage);
236        self
237    }
238
239    /// Set the measure for the processor.
240    pub fn measure(mut self, implement: PeriodicMeasure) -> Self {
241        self.measure = Some(Box::new(implement));
242        self
243    }
244
245    /// Set the number of DHT finger-table slots for the processor's swarm.
246    pub fn dht_finger_table_size(mut self, size: usize) -> Self {
247        self.dht_finger_table_size = size;
248        self
249    }
250
251    /// Set inbound chunk reassembly limits for the processor's swarm.
252    pub fn reassembly_limits(mut self, limits: ReassemblyLimits) -> Self {
253        self.reassembly_limits = limits;
254        self
255    }
256
257    /// Build the [Processor].
258    pub fn build(self) -> Result<Processor> {
259        self.session_sk
260            .session()
261            .verify_self()
262            .map_err(|e| Error::VerifyError(e.to_string()))?;
263
264        let storage = self.storage.unwrap_or_else(|| Box::new(MemStorage::new()));
265
266        let mut swarm_builder =
267            SwarmBuilder::new(self.network_id, &self.ice_servers, storage, self.session_sk);
268        swarm_builder = swarm_builder.dht_storage_redundancy(DATA_REDUNDANT);
269        swarm_builder = swarm_builder.dht_finger_table_size(self.dht_finger_table_size);
270        swarm_builder = swarm_builder.reassembly_limits(self.reassembly_limits);
271
272        if let Some(external_address) = self.external_address {
273            swarm_builder = swarm_builder.external_address(external_address);
274        }
275
276        if let Some(measure) = self.measure {
277            swarm_builder = swarm_builder.measure(measure);
278        }
279        let swarm = Arc::new(swarm_builder.build());
280
281        Ok(Processor {
282            swarm,
283            stabilize_interval: self.stabilize_interval,
284        })
285    }
286}
287
288impl Processor {
289    /// Get current did
290    pub fn did(&self) -> Did {
291        self.swarm.did()
292    }
293
294    /// Run stabilization daemon
295    pub async fn listen(&self) {
296        let stabilizer = self.swarm.stabilizer();
297        Arc::new(stabilizer).wait(self.stabilize_interval).await
298    }
299
300    /// Connect peer with web3 did.
301    /// There are 3 peers: PeerA, PeerB, PeerC.
302    /// 1. PeerA has a connection with PeerB.
303    /// 2. PeerC has a connection with PeerB.
304    /// 3. PeerC can connect PeerA with PeerA's web3 address.
305    pub async fn connect_with_did(&self, did: Did) -> Result<()> {
306        self.swarm.connect(did).await.map_err(Error::ConnectError)?;
307        Ok(())
308    }
309
310    /// Disconnect a peer with web3 did.
311    pub async fn disconnect(&self, did: Did) -> Result<()> {
312        self.swarm
313            .disconnect(did)
314            .await
315            .map_err(Error::CloseConnectionError)
316    }
317
318    /// Send custom message to a did.
319    pub async fn send_message(&self, destination: Did, msg: &[u8]) -> Result<uuid::Uuid> {
320        tracing::info!("send_message, message size: {:?}", msg.len());
321
322        let msg = Message::custom(msg).map_err(Error::SendMessage)?;
323
324        self.swarm
325            .send_message(msg, destination)
326            .await
327            .map_err(Error::SendMessage)
328    }
329
330    /// Send an E2E handshake request to a DID.
331    ///
332    /// The negotiated key is the peer's account/identity secp256k1 key, not
333    /// the ephemeral session key.
334    pub async fn send_e2e_handshake(&self, destination: Did) -> Result<uuid::Uuid> {
335        let public_key = self.swarm.account_pubkey().map_err(Error::SendMessage)?;
336        self.swarm
337            .send_message(
338                Message::E2eHandshakeRequest(E2eHandshakeRequest::new(public_key)),
339                destination,
340            )
341            .await
342            .map_err(Error::SendMessage)
343    }
344
345    /// Send an ElGamal-encrypted E2E message to a DID with a verified recipient key.
346    ///
347    /// Returns the stream id shared by all emitted E2E stream frames.
348    pub async fn send_e2e_message(
349        &self,
350        destination: Did,
351        recipient_public_key: PublicKey<33>,
352        msg: &[u8],
353    ) -> Result<uuid::Uuid> {
354        self.send_e2e_message_with_frame_len(
355            destination,
356            recipient_public_key,
357            msg,
358            e2e::DEFAULT_E2E_PLAINTEXT_FRAME_LEN,
359        )
360        .await
361    }
362
363    /// Send an ElGamal-encrypted E2E stream with an explicit plaintext frame size.
364    ///
365    /// Returns the stream id shared by all emitted E2E stream frames.
366    pub async fn send_e2e_message_with_frame_len(
367        &self,
368        destination: Did,
369        recipient_public_key: PublicKey<33>,
370        msg: &[u8],
371        max_plaintext_frame_len: usize,
372    ) -> Result<uuid::Uuid> {
373        e2e::ensure_public_key_matches_did(recipient_public_key, destination)
374            .map_err(Error::SendMessage)?;
375        let sender_public_key = self.swarm.account_pubkey().map_err(Error::SendMessage)?;
376        let stream_id = uuid::Uuid::new_v4();
377        let frames = e2e::encrypt_stream_frames(
378            msg,
379            stream_id,
380            sender_public_key,
381            recipient_public_key,
382            max_plaintext_frame_len,
383        )
384        .map_err(Error::SendMessage)?;
385
386        for frame in frames {
387            let frame = frame.map_err(Error::SendMessage)?;
388            self.swarm
389                .send_message(Message::E2eStreamFrame(frame), destination)
390                .await
391                .map_err(Error::SendMessage)?;
392        }
393
394        Ok(stream_id)
395    }
396
397    /// Verify an E2E handshake request and return the requester's identity public key.
398    pub fn verify_e2e_handshake_request(
399        &self,
400        requester: Did,
401        request: &E2eHandshakeRequest,
402    ) -> Result<PublicKey<33>> {
403        request
404            .verify_requester(requester)
405            .map_err(Error::CoreError)?;
406        Ok(request.requester_public_key)
407    }
408
409    /// Verify an E2E handshake response and return the responder's identity public key.
410    pub fn verify_e2e_handshake_response(
411        &self,
412        responder: Did,
413        response: &E2eHandshakeResponse,
414    ) -> Result<PublicKey<33>> {
415        response
416            .verify_responder(responder)
417            .map_err(Error::CoreError)?;
418        Ok(response.responder_public_key)
419    }
420
421    /// Create an E2E stream decryptor with this node's identity/signing secret key.
422    ///
423    /// The ciphertext is encrypted to the DID/account key negotiated by the
424    /// handshake. A session private key cannot decrypt it unless the session key
425    /// is also the account key, so callers must supply the local identity key
426    /// explicitly.
427    pub fn e2e_stream_decryptor(
428        &self,
429        expected_sender: Did,
430        stream_id: e2e::E2eStreamId,
431        recipient_identity_key: SecretKey,
432    ) -> Result<E2eStreamDecryptor> {
433        e2e::ensure_public_key_matches_did(recipient_identity_key.pubkey(), self.did())
434            .map_err(Error::CoreError)?;
435        Ok(E2eStreamDecryptor::new(
436            stream_id,
437            expected_sender,
438            recipient_identity_key,
439        ))
440    }
441
442    /// Decrypt one E2E stream frame with an already-created stream decryptor.
443    pub fn decrypt_e2e_stream_frame(
444        &self,
445        decryptor: &mut E2eStreamDecryptor,
446        frame: &E2eStreamFrame,
447    ) -> Result<Vec<u8>> {
448        decryptor.decrypt_next(frame).map_err(Error::CoreError)
449    }
450
451    /// Send a namespaced [`Envelope`](crate::extension::ext::Envelope) to a did over the
452    /// P2P transport (the wire codec
453    /// of the extension layer). `send_envelope : (Did, Envelope) → IO TxId`.
454    pub async fn send_envelope(
455        &self,
456        destination: Did,
457        envelope: &crate::extension::ext::Envelope,
458    ) -> Result<uuid::Uuid> {
459        let msg_bytes = envelope.encode()?;
460        self.send_message(destination, &msg_bytes).await
461    }
462
463    /// check local cache of dht
464    pub async fn storage_check_cache(&self, entry_key: Did) -> Option<entry::Entry> {
465        self.swarm.storage_check_cache(entry_key).await
466    }
467
468    /// Fetch an entry from DHT storage
469    pub async fn storage_fetch(&self, entry_key: Did) -> Result<()> {
470        <Swarm as ChordStorageInterface<DATA_REDUNDANT>>::storage_fetch(&self.swarm, entry_key)
471            .await
472            .map_err(Error::EntryError)
473    }
474
475    /// Store an entry on DHT storage
476    pub async fn storage_store(&self, entry: entry::Entry) -> Result<()> {
477        <Swarm as ChordStorageInterface<DATA_REDUNDANT>>::storage_store(&self.swarm, entry)
478            .await
479            .map_err(Error::EntryError)
480    }
481
482    /// Append data to an entry on DHT storage
483    pub async fn storage_append_data(&self, topic: &str, data: Encoded) -> Result<()> {
484        <Swarm as ChordStorageInterface<DATA_REDUNDANT>>::storage_append_data(
485            &self.swarm,
486            topic,
487            data,
488        )
489        .await
490        .map_err(Error::EntryError)
491    }
492
493    /// register service
494    pub async fn register_service(&self, name: &str) -> Result<()> {
495        let encoded_did = self
496            .did()
497            .to_string()
498            .encode()
499            .map_err(Error::ServiceRegisterError)?;
500        <Swarm as ChordStorageInterface<DATA_REDUNDANT>>::storage_touch_data(
501            &self.swarm,
502            name,
503            encoded_did,
504        )
505        .await
506        .map_err(Error::ServiceRegisterError)
507    }
508
509    /// get node info
510    pub async fn get_node_info(&self) -> Result<NodeInfoResponse> {
511        Ok(NodeInfoResponse {
512            version: crate::util::build_version(),
513            swarm: Some(self.swarm.inspect().await.into()),
514        })
515    }
516}
517
518#[cfg(test)]
519#[cfg(feature = "node")]
520mod test {
521    use std::sync::Mutex;
522    use std::time::Duration;
523    use std::time::Instant;
524
525    use rings_core::storage::MemStorage;
526    use rings_core::swarm::callback::SwarmCallback;
527    use rings_core::swarm::callback::SwarmEvent;
528    use rings_transport::core::transport::WebrtcConnectionState;
529    use tokio::sync::Notify;
530
531    use super::*;
532    use crate::prelude::*;
533    use crate::tests::native::prepare_processor;
534
535    #[tokio::test]
536    async fn test_processor_create_offer() {
537        let peer_did = SecretKey::random().address().into();
538        let processor = prepare_processor().await;
539        processor.swarm.create_offer(peer_did).await.unwrap();
540        let conn_dids = processor.swarm.peers();
541        assert_eq!(conn_dids.len(), 1);
542        assert_eq!(conn_dids.first().unwrap().did, peer_did.to_string());
543    }
544
545    struct SwarmCallbackInstance {
546        inbound: Mutex<Vec<Message>>,
547        inbound_notify: Notify,
548        connected_notify: Notify,
549    }
550
551    #[async_trait]
552    impl SwarmCallback for SwarmCallbackInstance {
553        async fn on_inbound(
554            &self,
555            payload: &MessagePayload,
556        ) -> std::result::Result<(), Box<dyn std::error::Error>> {
557            let msg: Message = payload.transaction.data().map_err(Box::new)?;
558            {
559                let mut inbound = self.inbound.lock().unwrap();
560                inbound.push(msg);
561            }
562            self.inbound_notify.notify_one();
563
564            Ok(())
565        }
566
567        async fn on_event(
568            &self,
569            event: &SwarmEvent,
570        ) -> std::result::Result<(), Box<dyn std::error::Error>> {
571            if let SwarmEvent::ConnectionStateChange {
572                state: WebrtcConnectionState::Connected,
573                ..
574            } = event
575            {
576                self.connected_notify.notify_one();
577            }
578
579            Ok(())
580        }
581    }
582
583    fn test_callback() -> Arc<SwarmCallbackInstance> {
584        Arc::new(SwarmCallbackInstance {
585            inbound: Mutex::new(Vec::new()),
586            inbound_notify: Notify::new(),
587            connected_notify: Notify::new(),
588        })
589    }
590
591    async fn prepare_processor_with_identity_key(identity_key: SecretKey) -> Processor {
592        let session_sk = SessionSk::new_with_seckey(&identity_key).unwrap();
593        let config = ProcessorConfig::new(
594            0,
595            "stun://stun.l.google.com:19302".to_string(),
596            session_sk,
597            3,
598        );
599        let storage = Box::new(MemStorage::new());
600
601        ProcessorBuilder::from_config(&config)
602            .unwrap()
603            .storage(storage)
604            .dht_finger_table_size(8)
605            .build()
606            .unwrap()
607    }
608
609    async fn connect_processors(
610        p1: &Processor,
611        p2: &Processor,
612        callback1: &SwarmCallbackInstance,
613        callback2: &SwarmCallbackInstance,
614    ) {
615        let offer = p1.swarm.create_offer(p2.did()).await.unwrap();
616        let answer = p2.swarm.answer_offer(offer).await.unwrap();
617        p1.swarm.accept_answer(answer).await.unwrap();
618        wait_processors_connected(p1, p2, callback1, callback2).await;
619    }
620
621    async fn wait_processors_connected(
622        p1: &Processor,
623        p2: &Processor,
624        callback1: &SwarmCallbackInstance,
625        callback2: &SwarmCallbackInstance,
626    ) {
627        let deadline = Instant::now() + Duration::from_secs(5);
628        loop {
629            if processor_has_connected_peer(p1, p2.did())
630                && processor_has_connected_peer(p2, p1.did())
631            {
632                return;
633            }
634
635            let remaining = deadline
636                .checked_duration_since(Instant::now())
637                .expect("processors did not connect");
638            tokio::time::timeout(remaining, async {
639                tokio::select! {
640                    _ = callback1.connected_notify.notified() => {}
641                    _ = callback2.connected_notify.notified() => {}
642                }
643            })
644            .await
645            .expect("processors did not connect");
646        }
647    }
648
649    fn processor_has_connected_peer(processor: &Processor, peer: Did) -> bool {
650        let peer = peer.to_string();
651        processor
652            .swarm
653            .peers()
654            .into_iter()
655            .any(|conn| conn.did == peer && conn.state == "Connected")
656    }
657
658    async fn wait_for_inbound_message(
659        callback: &SwarmCallbackInstance,
660        predicate: impl Fn(&Message) -> bool,
661    ) -> Message {
662        let deadline = Instant::now() + Duration::from_secs(5);
663        loop {
664            {
665                let inbound = callback.inbound.lock().unwrap();
666                if let Some(msg) = inbound.iter().find(|msg| predicate(msg)).cloned() {
667                    return msg;
668                }
669            }
670
671            let remaining = deadline
672                .checked_duration_since(Instant::now())
673                .expect("inbound message was not delivered");
674            tokio::time::timeout(remaining, callback.inbound_notify.notified())
675                .await
676                .expect("inbound message was not delivered");
677        }
678    }
679
680    async fn wait_for_e2e_stream_frames(
681        callback: &SwarmCallbackInstance,
682        stream_id: e2e::E2eStreamId,
683    ) -> Vec<E2eStreamFrame> {
684        let deadline = Instant::now() + Duration::from_secs(5);
685        loop {
686            {
687                let inbound = callback.inbound.lock().unwrap();
688                let frames = inbound
689                    .iter()
690                    .filter_map(|msg| match msg {
691                        Message::E2eStreamFrame(frame) if frame.stream_id == stream_id => {
692                            Some(frame.clone())
693                        }
694                        _ => None,
695                    })
696                    .collect::<Vec<_>>();
697                if frames.iter().any(|frame| frame.is_final) {
698                    return frames;
699                }
700            }
701
702            let remaining = deadline
703                .checked_duration_since(Instant::now())
704                .expect("E2E stream final frame was not delivered");
705            tokio::time::timeout(remaining, callback.inbound_notify.notified())
706                .await
707                .expect("E2E stream final frame was not delivered");
708        }
709    }
710
711    #[tokio::test]
712    async fn test_processor_handshake_msg() {
713        let callback1 = test_callback();
714        let callback2 = test_callback();
715
716        let p1 = prepare_processor().await;
717        let p2 = prepare_processor().await;
718
719        p1.swarm.set_callback(callback1.clone()).unwrap();
720        p2.swarm.set_callback(callback2.clone()).unwrap();
721
722        let did1 = p1.did();
723        let did2 = p2.did();
724
725        let offer = p1.swarm.create_offer(p2.did()).await.unwrap();
726        assert_eq!(
727            p1.swarm
728                .peers()
729                .into_iter()
730                .find(|peer| peer.did == p2.did().to_string())
731                .unwrap()
732                .state,
733            "New"
734        );
735
736        let answer = p2.swarm.answer_offer(offer).await.unwrap();
737        p1.swarm.accept_answer(answer).await.unwrap();
738        wait_processors_connected(&p1, &p2, &callback1, &callback2).await;
739
740        let test_text1 = "test1";
741        let test_text2 = "test2";
742
743        p1.send_message(did2, test_text1.as_bytes()).await.unwrap();
744        p2.send_message(did1, test_text2.as_bytes()).await.unwrap();
745
746        let got_msg2 = wait_for_inbound_message(&callback2, |msg| {
747            matches!(msg, Message::CustomMessage(custom) if custom.0 == test_text1.as_bytes())
748        })
749        .await;
750        assert!(matches!(got_msg2, Message::CustomMessage(_)));
751
752        let got_msg1 = wait_for_inbound_message(&callback1, |msg| {
753            matches!(msg, Message::CustomMessage(custom) if custom.0 == test_text2.as_bytes())
754        })
755        .await;
756        assert!(matches!(got_msg1, Message::CustomMessage(_)));
757    }
758
759    #[tokio::test]
760    async fn test_processor_e2e_handshake_exchanges_verified_public_keys() {
761        let callback1 = test_callback();
762        let callback2 = test_callback();
763
764        let p1 = prepare_processor().await;
765        let p2 = prepare_processor().await;
766
767        p1.swarm.set_callback(callback1.clone()).unwrap();
768        p2.swarm.set_callback(callback2.clone()).unwrap();
769
770        connect_processors(&p1, &p2, &callback1, &callback2).await;
771
772        let did1 = p1.did();
773        let did2 = p2.did();
774        let requester_public_key = p1.swarm.account_pubkey().unwrap();
775        let responder_public_key = p2.swarm.account_pubkey().unwrap();
776
777        p1.send_e2e_handshake(did2).await.unwrap();
778
779        let request = wait_for_inbound_message(&callback2, |msg| {
780            matches!(msg, Message::E2eHandshakeRequest(_))
781        })
782        .await;
783        match request {
784            Message::E2eHandshakeRequest(request) => {
785                assert_eq!(request.requester_public_key, requester_public_key);
786                assert_eq!(
787                    p2.verify_e2e_handshake_request(did1, &request).unwrap(),
788                    requester_public_key
789                );
790            }
791            msg => panic!("expected E2eHandshakeRequest, got {msg:?}"),
792        }
793
794        let response = wait_for_inbound_message(&callback1, |msg| {
795            matches!(msg, Message::E2eHandshakeResponse(_))
796        })
797        .await;
798        match response {
799            Message::E2eHandshakeResponse(response) => {
800                assert_eq!(response.responder_public_key, responder_public_key);
801                assert_eq!(
802                    p1.verify_e2e_handshake_response(did2, &response).unwrap(),
803                    responder_public_key
804                );
805            }
806            msg => panic!("expected E2eHandshakeResponse, got {msg:?}"),
807        }
808    }
809
810    #[tokio::test]
811    async fn test_processor_e2e_message_streams_and_decrypts_with_receiver_identity_key() {
812        let callback1 = test_callback();
813        let callback2 = test_callback();
814        let identity1 = SecretKey::random();
815        let identity2 = SecretKey::random();
816
817        let p1 = prepare_processor_with_identity_key(identity1).await;
818        let p2 = prepare_processor_with_identity_key(identity2).await;
819
820        p1.swarm.set_callback(callback1.clone()).unwrap();
821        p2.swarm.set_callback(callback2.clone()).unwrap();
822
823        connect_processors(&p1, &p2, &callback1, &callback2).await;
824
825        let did1 = p1.did();
826        let did2 = p2.did();
827        let responder_public_key = p2.swarm.account_pubkey().unwrap();
828        let stream_id = p1
829            .send_e2e_message_with_frame_len(
830                did2,
831                responder_public_key,
832                b"homomorphic-ready streaming body",
833                8,
834            )
835            .await
836            .unwrap();
837
838        let frames = wait_for_e2e_stream_frames(&callback2, stream_id).await;
839        assert!(
840            frames.len() > 1,
841            "streaming send should emit more than one frame for this frame size"
842        );
843        assert_eq!(
844            frames.iter().filter(|frame| frame.is_final).count(),
845            1,
846            "streaming send should emit exactly one final frame"
847        );
848
849        let mut sequences = frames
850            .iter()
851            .map(|frame| frame.sequence)
852            .collect::<Vec<_>>();
853        sequences.sort_unstable();
854        let frame_count = u64::try_from(frames.len()).unwrap();
855        assert_eq!(sequences, (0..frame_count).collect::<Vec<_>>());
856
857        let mut decryptor = p2.e2e_stream_decryptor(did1, stream_id, identity2).unwrap();
858        let mut plaintext = Vec::new();
859        let mut delivered_frames = frames.clone();
860        delivered_frames.reverse();
861        for frame in &delivered_frames {
862            plaintext
863                .extend_from_slice(&p2.decrypt_e2e_stream_frame(&mut decryptor, frame).unwrap());
864        }
865        decryptor.finish().unwrap();
866        assert_eq!(plaintext, b"homomorphic-ready streaming body");
867
868        assert!(matches!(
869            p2.e2e_stream_decryptor(did1, stream_id, SecretKey::random()),
870            Err(Error::CoreError(
871                rings_core::error::Error::E2ePublicKeyDidMismatch { .. }
872            ))
873        ));
874    }
875}