1use std::collections::{hash_map::RandomState, HashSet};
2use std::fmt::{Display, Formatter};
3use std::hash::Hash;
4
5use futures::future::FutureExt;
6use futures::stream::FuturesOrdered;
7use futures::TryStreamExt;
8use libp2p_identity::PeerId;
9
10use hopr_crypto_types::types::OffchainPublicKey;
11use hopr_db_api::resolver::HoprDbResolverOperations;
12use hopr_internal_types::channels::ChannelStatus;
13use hopr_primitive_types::{primitives::Address, traits::ToHex};
14
15use crate::channel_graph::ChannelGraph;
16use crate::errors::PathError;
17use crate::errors::PathError::{ChannelNotOpened, InvalidPeer, LoopsNotAllowed, MissingChannel, PathNotValid};
18use crate::errors::Result;
19
20pub trait Path<N>: Display + Clone + Eq + PartialEq
23where
24 N: Copy + Clone + Eq + PartialEq + Hash,
25{
26 fn hops(&self) -> &[N];
29
30 fn length(&self) -> usize {
32 self.hops().len()
33 }
34
35 fn last_hop(&self) -> &N {
37 self.hops().last().expect("path is invalid")
39 }
40
41 fn contains_cycle(&self) -> bool {
45 let set = HashSet::<&N, RandomState>::from_iter(self.hops().iter());
46 set.len() != self.hops().len()
47 }
48}
49
50#[derive(Debug, Clone, PartialEq, Eq)]
59pub struct ChannelPath {
60 pub(crate) hops: Vec<Address>,
61}
62
63impl ChannelPath {
64 pub fn new(hops: Vec<Address>, graph: &ChannelGraph) -> Result<Self> {
71 if hops.is_empty() || hops[0] == graph.my_address() {
72 return Err(PathNotValid);
73 }
74
75 let mut ticket_receiver;
76 let mut ticket_issuer = graph.my_address();
77
78 for hop in hops.iter() {
79 ticket_receiver = *hop;
80
81 if ticket_issuer == ticket_receiver {
83 return Err(LoopsNotAllowed(ticket_receiver.to_hex()));
84 }
85
86 let channel = graph
88 .get_channel(&ticket_issuer, &ticket_receiver)
89 .ok_or(MissingChannel(ticket_issuer.to_hex(), ticket_receiver.to_hex()))?;
90
91 if channel.status != ChannelStatus::Open {
92 return Err(ChannelNotOpened(ticket_issuer.to_hex(), ticket_receiver.to_hex()));
93 }
94
95 ticket_issuer = ticket_receiver;
96 }
97
98 Ok(Self { hops })
99 }
100
101 pub(crate) fn new_valid(hops: Vec<Address>) -> Self {
103 assert!(!hops.is_empty(), "must not be empty");
104 Self { hops }
105 }
106
107 pub async fn into_path<R: HoprDbResolverOperations>(
111 self,
112 resolver: &R,
113 destination: Address,
114 ) -> Result<TransportPath> {
115 let mut hops = self
116 .hops
117 .iter()
118 .map(|addr| {
119 resolver
120 .resolve_packet_key(addr)
121 .map(move |opt| opt?.map(PeerId::from).ok_or(InvalidPeer(addr.to_string())))
122 })
123 .collect::<FuturesOrdered<_>>()
124 .try_collect::<Vec<PeerId>>()
125 .await?;
126
127 let last_hop = resolver
128 .resolve_packet_key(&destination)
129 .await?
130 .ok_or(InvalidPeer(destination.to_string()))?;
131
132 hops.push(last_hop.into());
133 Ok(TransportPath::new_valid(hops))
134 }
135}
136
137impl Path<Address> for ChannelPath {
138 fn hops(&self) -> &[Address] {
139 &self.hops
140 }
141}
142
143impl Display for ChannelPath {
144 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
145 write!(
146 f,
147 "[ {} ] ({} hops)",
148 self.hops.iter().map(|p| p.to_string()).collect::<Vec<_>>().join("->"),
149 self.hops.len()
150 )
151 }
152}
153
154#[derive(Debug, Clone, PartialEq, Eq)]
161pub struct TransportPath {
162 hops: Vec<PeerId>,
163}
164
165impl TransportPath {
166 pub async fn resolve<R: HoprDbResolverOperations>(
177 peers: Vec<PeerId>,
178 resolver: &R,
179 graph: &ChannelGraph,
180 ) -> Result<(Self, Option<ChannelPath>)> {
181 if peers.is_empty() {
182 Err(PathNotValid)
183 } else if peers.len() == 1 {
184 Ok((Self { hops: peers }, None))
185 } else {
186 let (mut addrs, hops): (Vec<Address>, Vec<PeerId>) = peers
187 .into_iter()
188 .map(|peer| async move {
189 let key = OffchainPublicKey::try_from(peer)?;
190 resolver
191 .resolve_chain_key(&key)
192 .await?
193 .map(|addr| (addr, peer))
194 .ok_or(InvalidPeer(peer.to_string()))
195 })
196 .collect::<FuturesOrdered<_>>()
197 .try_collect::<Vec<_>>()
198 .await?
199 .into_iter()
200 .unzip();
201
202 addrs.pop(); Ok((Self { hops }, Some(ChannelPath::new(addrs, graph)?)))
204 }
205 }
206
207 pub fn direct(destination: PeerId) -> Self {
209 Self {
210 hops: vec![destination],
211 }
212 }
213
214 pub(crate) fn new_valid(hops: Vec<PeerId>) -> Self {
216 assert!(!hops.is_empty(), "must not be empty");
217 Self { hops }
218 }
219}
220
221impl Path<PeerId> for TransportPath {
222 fn hops(&self) -> &[PeerId] {
225 &self.hops
226 }
227}
228
229impl<T> TryFrom<&TransportPath> for Vec<T>
230where
231 T: TryFrom<PeerId>,
232{
233 type Error = PathError;
234
235 fn try_from(value: &TransportPath) -> std::result::Result<Self, Self::Error> {
236 value
237 .hops()
238 .iter()
239 .map(|p| T::try_from(*p).map_err(|_| InvalidPeer(p.to_string())))
240 .collect()
241 }
242}
243
244impl Display for TransportPath {
245 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
246 write!(
247 f,
248 "[ {} ] ({} hops)",
249 self.hops.iter().map(|p| p.to_string()).collect::<Vec<_>>().join("->"),
250 self.length() - 1
251 )
252 }
253}
254
255#[cfg(test)]
256mod tests {
257 use super::*;
258 use anyhow::Context;
259 use async_trait::async_trait;
260 use hex_literal::hex;
261 use hopr_crypto_types::prelude::*;
262 use hopr_internal_types::channels::ChannelEntry;
263 use hopr_primitive_types::prelude::*;
264 use std::ops::Add;
265 use std::time::{Duration, SystemTime};
266
267 const PEERS_PRIVS: [[u8; 32]; 5] = [
268 hex!("492057cf93e99b31d2a85bc5e98a9c3aa0021feec52c227cc8170e8f7d047775"),
269 hex!("5bf21ea8cccd69aa784346b07bf79c84dac606e00eecaa68bf8c31aff397b1ca"),
270 hex!("3477d7de923ba3a7d5d72a7d6c43fd78395453532d03b2a1e2b9a7cc9b61bafa"),
271 hex!("db7e3e8fcac4c817aa4cecee1d6e2b4d53da51f9881592c0e1cc303d8a012b92"),
272 hex!("0726a9704d56a013980a9077d195520a61b5aed28f92d89c50bca6e0e0c48cfc"),
273 ];
274
275 fn dummy_channel(src: Address, dst: Address, status: ChannelStatus) -> ChannelEntry {
276 ChannelEntry::new(
277 src,
278 dst,
279 Balance::new_from_str("1", BalanceType::HOPR),
280 1u32.into(),
281 status,
282 1u32.into(),
283 )
284 }
285
286 fn create_graph_and_resolver_entries(me: Address) -> (ChannelGraph, Vec<(OffchainPublicKey, Address)>) {
287 let mut cg = ChannelGraph::new(me, Default::default());
288 let addrs = PEERS_PRIVS
289 .iter()
290 .map(|p| {
291 (
292 OffchainPublicKey::from_privkey(p).unwrap(),
293 PublicKey::from_privkey(p).unwrap().to_address(),
294 )
295 })
296 .collect::<Vec<_>>();
297
298 let ts = SystemTime::now().add(Duration::from_secs(10));
299
300 cg.update_channel(dummy_channel(addrs[0].1, addrs[1].1, ChannelStatus::Open));
302 cg.update_channel(dummy_channel(addrs[1].1, addrs[2].1, ChannelStatus::Open));
303 cg.update_channel(dummy_channel(addrs[2].1, addrs[3].1, ChannelStatus::Open));
304 cg.update_channel(dummy_channel(addrs[3].1, addrs[4].1, ChannelStatus::Open));
305 cg.update_channel(dummy_channel(addrs[3].1, addrs[1].1, ChannelStatus::Open));
306 cg.update_channel(dummy_channel(addrs[4].1, addrs[0].1, ChannelStatus::PendingToClose(ts)));
307
308 (cg, addrs)
309 }
310
311 #[test]
312 fn test_channel_path_zero_hop_should_fail() -> anyhow::Result<()> {
313 let me = PublicKey::from_privkey(&PEERS_PRIVS[0]).unwrap().to_address();
314 let (cg, _) = create_graph_and_resolver_entries(me);
315
316 ChannelPath::new(vec![], &cg).expect_err("path must not be constructible");
317
318 Ok(())
319 }
320
321 #[test]
322 fn test_channel_path_one_hop() -> anyhow::Result<()> {
323 let me = PublicKey::from_privkey(&PEERS_PRIVS[0]).unwrap().to_address();
324 let (cg, peer_addrs) = create_graph_and_resolver_entries(me);
325 let (_, addrs): (Vec<OffchainPublicKey>, Vec<Address>) = peer_addrs.into_iter().unzip();
326
327 let cp = ChannelPath::new(vec![addrs[1]], &cg)?;
329 assert_eq!(1, cp.length(), "must be one hop");
330 assert!(!cp.contains_cycle(), "must not be cyclic");
331 Ok(())
332 }
333
334 #[test]
335 fn test_channel_path_two_hop() -> anyhow::Result<()> {
336 let me = PublicKey::from_privkey(&PEERS_PRIVS[0]).unwrap().to_address();
337 let (cg, peer_addrs) = create_graph_and_resolver_entries(me);
338 let (_, addrs): (Vec<OffchainPublicKey>, Vec<Address>) = peer_addrs.into_iter().unzip();
339
340 let cp = ChannelPath::new(vec![addrs[1], addrs[2]], &cg)?;
342 assert_eq!(2, cp.length(), "must be two hop");
343 assert!(!cp.contains_cycle(), "must not be cyclic");
344 Ok(())
345 }
346
347 #[test]
348 fn test_channel_path_three_hop() -> anyhow::Result<()> {
349 let me = PublicKey::from_privkey(&PEERS_PRIVS[0]).unwrap().to_address();
350 let (cg, peer_addrs) = create_graph_and_resolver_entries(me);
351 let (_, addrs): (Vec<OffchainPublicKey>, Vec<Address>) = peer_addrs.into_iter().unzip();
352
353 let cp = ChannelPath::new(vec![addrs[1], addrs[2], addrs[3]], &cg)?;
355 assert_eq!(3, cp.length(), "must be three hop");
356 assert!(!cp.contains_cycle(), "must not be cyclic");
357 Ok(())
358 }
359
360 #[test]
361 fn test_channel_path_must_allow_cyclic() -> anyhow::Result<()> {
362 let me = PublicKey::from_privkey(&PEERS_PRIVS[0]).unwrap().to_address();
363 let (cg, peer_addrs) = create_graph_and_resolver_entries(me);
364 let (_, addrs): (Vec<OffchainPublicKey>, Vec<Address>) = peer_addrs.into_iter().unzip();
365
366 let cp = ChannelPath::new(vec![addrs[1], addrs[2], addrs[3], addrs[1]], &cg)?;
368 assert_eq!(4, cp.length(), "must be four hop");
369 assert!(cp.contains_cycle(), "must not be cyclic");
370 Ok(())
371 }
372
373 #[test]
374 fn test_channel_path_should_fail_for_non_open_channel() -> anyhow::Result<()> {
375 let me = PublicKey::from_privkey(&PEERS_PRIVS[0]).unwrap().to_address();
376 let (cg, peer_addrs) = create_graph_and_resolver_entries(me);
377 let (_, addrs): (Vec<OffchainPublicKey>, Vec<Address>) = peer_addrs.into_iter().unzip();
378
379 ChannelPath::new(vec![addrs[4], addrs[0]], &cg).expect_err("path must not be constructible");
381 Ok(())
382 }
383
384 #[test]
385 fn test_channel_path_should_fail_for_non_open_channel_from_self() -> anyhow::Result<()> {
386 let me = PublicKey::from_privkey(&PEERS_PRIVS[4]).unwrap().to_address();
387 let (cg, peer_addrs) = create_graph_and_resolver_entries(me);
388 let (_, addrs): (Vec<OffchainPublicKey>, Vec<Address>) = peer_addrs.into_iter().unzip();
389
390 ChannelPath::new(vec![addrs[4], addrs[0]], &cg).expect_err("path must not be constructible");
392 Ok(())
393 }
394
395 #[test]
396 fn test_channel_path_should_fail_for_non_existing_channel() -> anyhow::Result<()> {
397 let me = PublicKey::from_privkey(&PEERS_PRIVS[0]).unwrap().to_address();
398 let (cg, peer_addrs) = create_graph_and_resolver_entries(me);
399 let (_, addrs): (Vec<OffchainPublicKey>, Vec<Address>) = peer_addrs.into_iter().unzip();
400
401 ChannelPath::new(vec![addrs[1], addrs[3]], &cg).expect_err("path 1 must not be constructible");
403
404 ChannelPath::new(vec![addrs[1], addrs[2], addrs[4]], &cg).expect_err("path 2 must not be constructible");
406 Ok(())
407 }
408
409 #[test]
410 fn test_channel_path_should_not_allow_loops() -> anyhow::Result<()> {
411 let me = PublicKey::from_privkey(&PEERS_PRIVS[0]).unwrap().to_address();
412 let (cg, peer_addrs) = create_graph_and_resolver_entries(me);
413 let (_, addrs): (Vec<OffchainPublicKey>, Vec<Address>) = peer_addrs.into_iter().unzip();
414
415 ChannelPath::new(vec![addrs[1], addrs[1], addrs[0]], &cg).expect_err("path must not be constructible");
417 Ok(())
418 }
419
420 struct TestResolver(Vec<(OffchainPublicKey, Address)>);
421
422 #[async_trait]
423 impl HoprDbResolverOperations for TestResolver {
424 async fn resolve_packet_key(
425 &self,
426 onchain_key: &Address,
427 ) -> hopr_db_sql::api::errors::Result<Option<OffchainPublicKey>> {
428 Ok(self.0.iter().find(|(_, addr)| addr.eq(onchain_key)).map(|(pk, _)| *pk))
429 }
430
431 async fn resolve_chain_key(
432 &self,
433 offchain_key: &OffchainPublicKey,
434 ) -> hopr_db_sql::api::errors::Result<Option<Address>> {
435 Ok(self.0.iter().find(|(pk, _)| pk.eq(offchain_key)).map(|(_, addr)| *addr))
436 }
437 }
438
439 #[async_std::test]
440 async fn test_transport_path_empty_should_fail() -> anyhow::Result<()> {
441 let me = PublicKey::from_privkey(&PEERS_PRIVS[0]).unwrap().to_address();
442 let (cg, peer_addrs) = create_graph_and_resolver_entries(me);
443 let resolver = TestResolver(peer_addrs.clone());
444
445 TransportPath::resolve(vec![], &resolver, &cg)
446 .await
447 .expect_err("should not resolve path");
448 Ok(())
449 }
450
451 fn make_address_pairs(peer_addrs: Vec<(OffchainPublicKey, Address)>) -> (Vec<PeerId>, Vec<Address>) {
452 peer_addrs.into_iter().map(|(p, a)| (PeerId::from(p), a)).unzip()
453 }
454
455 #[async_std::test]
456 async fn test_transport_path_resolve_direct() -> anyhow::Result<()> {
457 let me = PublicKey::from_privkey(&PEERS_PRIVS[0]).unwrap().to_address();
458 let (cg, peer_addrs) = create_graph_and_resolver_entries(me);
459 let resolver = TestResolver(peer_addrs.clone());
460 let (peers, _) = make_address_pairs(peer_addrs);
461
462 let (p, cp) = TransportPath::resolve(vec![peers[1]], &resolver, &cg).await?;
464 assert_eq!(1, p.length(), "must contain destination");
465 assert!(cp.is_none(), "no channel path for direct message");
466
467 Ok(())
468 }
469
470 #[async_std::test]
471 async fn test_transport_path_resolve_direct_to_self() -> anyhow::Result<()> {
472 let me = PublicKey::from_privkey(&PEERS_PRIVS[0]).unwrap().to_address();
473 let (cg, peer_addrs) = create_graph_and_resolver_entries(me);
474 let resolver = TestResolver(peer_addrs.clone());
475 let (peers, _) = make_address_pairs(peer_addrs);
476
477 let (p, cp) = TransportPath::resolve(vec![peers[0]], &resolver, &cg).await?;
479 assert_eq!(1, p.length(), "must contain destination");
480 assert!(cp.is_none(), "no channel path for direct message");
481
482 Ok(())
483 }
484
485 #[async_std::test]
486 async fn test_transport_path_resolve_direct_is_allowed_without_channel_to_destination() -> anyhow::Result<()> {
487 let me = PublicKey::from_privkey(&PEERS_PRIVS[0]).unwrap().to_address();
488 let (cg, peer_addrs) = create_graph_and_resolver_entries(me);
489 let resolver = TestResolver(peer_addrs.clone());
490 let (peers, _) = make_address_pairs(peer_addrs);
491
492 let (p, cp) = TransportPath::resolve(vec![peers[3]], &resolver, &cg).await?;
494 assert_eq!(1, p.length(), "must contain destination");
495 assert!(cp.is_none(), "no channel path for direct message");
496 Ok(())
497 }
498
499 #[async_std::test]
500 async fn test_transport_path_resolve_direct_is_allowed_with_closed_channel_to_destination() -> anyhow::Result<()> {
501 let me = PublicKey::from_privkey(&PEERS_PRIVS[4]).unwrap().to_address();
502 let (cg, peer_addrs) = create_graph_and_resolver_entries(me);
503 let resolver = TestResolver(peer_addrs.clone());
504 let (peers, _) = make_address_pairs(peer_addrs);
505
506 let (p, cp) = TransportPath::resolve(vec![peers[0]], &resolver, &cg).await?;
508 assert_eq!(1, p.length(), "must contain destination");
509 assert!(cp.is_none(), "no channel path for direct message");
510
511 Ok(())
512 }
513
514 #[async_std::test]
515 async fn test_transport_path_resolve_one_hop() -> anyhow::Result<()> {
516 let me = PublicKey::from_privkey(&PEERS_PRIVS[0]).unwrap().to_address();
517 let (cg, peer_addrs) = create_graph_and_resolver_entries(me);
518 let resolver = TestResolver(peer_addrs.clone());
519 let (peers, addrs) = make_address_pairs(peer_addrs);
520
521 let (p, cp) = TransportPath::resolve(vec![peers[1], peers[2]], &resolver, &cg).await?;
523 assert_eq!(2, p.length(), "must be two hop");
524 assert!(!p.contains_cycle(), "transport path must not contain a cycle");
525
526 let cp = cp.context("must have channel path")?;
527 assert_eq!(1, cp.length(), "channel path must be one hop");
528 assert_eq!(vec![addrs[1]], cp.hops(), "channel path address must match");
529 assert!(!cp.contains_cycle(), "channel path must not contain a cycle");
530 Ok(())
531 }
532
533 #[async_std::test]
534 async fn test_transport_path_resolve_one_hop_without_channel_to_destination() -> anyhow::Result<()> {
535 let me = PublicKey::from_privkey(&PEERS_PRIVS[0]).unwrap().to_address();
536 let (cg, peer_addrs) = create_graph_and_resolver_entries(me);
537 let resolver = TestResolver(peer_addrs.clone());
538 let (peers, addrs) = make_address_pairs(peer_addrs);
539
540 let (p, cp) = TransportPath::resolve(vec![peers[1], peers[4]], &resolver, &cg).await?;
542 assert_eq!(2, p.length(), "must be two hop");
543 assert!(!p.contains_cycle(), "transport path must not contain a cycle");
544
545 let cp = cp.context("must have channel path")?;
546 assert_eq!(1, cp.length(), "channel path must be one hop");
547 assert_eq!(vec![addrs[1]], cp.hops(), "channel path address must match");
548 assert!(!cp.contains_cycle(), "channel path must not contain a cycle");
549 Ok(())
550 }
551
552 #[async_std::test]
553 async fn test_transport_path_resolve_two_hop() -> anyhow::Result<()> {
554 let me = PublicKey::from_privkey(&PEERS_PRIVS[0]).unwrap().to_address();
555 let (cg, peer_addrs) = create_graph_and_resolver_entries(me);
556 let resolver = TestResolver(peer_addrs.clone());
557 let (peers, addrs) = make_address_pairs(peer_addrs);
558
559 let (p, cp) = TransportPath::resolve(vec![peers[1], peers[2], peers[3]], &resolver, &cg).await?;
561 assert_eq!(3, p.length(), "must be three hop");
562 assert!(!p.contains_cycle(), "transport path must not contain a cycle");
563
564 let cp = cp.context("must have channel path")?;
565 assert_eq!(2, cp.length(), "channel path must be two hop");
566 assert_eq!(vec![addrs[1], addrs[2]], cp.hops(), "channel path address must match");
567 assert!(!cp.contains_cycle(), "channel path must not contain a cycle");
568 Ok(())
569 }
570
571 #[async_std::test]
572 async fn test_transport_path_resolve_two_hop_without_channel_to_destination() -> anyhow::Result<()> {
573 let me = PublicKey::from_privkey(&PEERS_PRIVS[0]).unwrap().to_address();
574 let (cg, peer_addrs) = create_graph_and_resolver_entries(me);
575 let resolver = TestResolver(peer_addrs.clone());
576 let (peers, addrs) = make_address_pairs(peer_addrs);
577
578 let (p, cp) = TransportPath::resolve(vec![peers[1], peers[2], peers[4]], &resolver, &cg).await?;
580 assert_eq!(3, p.length(), "must be three hop");
581 assert!(!p.contains_cycle(), "transport path must not contain a cycle");
582
583 let cp = cp.context("must have channel path")?;
584 assert_eq!(2, cp.length(), "channel path must be two hop");
585 assert_eq!(vec![addrs[1], addrs[2]], cp.hops(), "channel path address must match");
586 assert!(!cp.contains_cycle(), "channel path must not contain a cycle");
587 Ok(())
588 }
589
590 #[async_std::test]
591 async fn test_transport_path_resolve_three_hop() -> anyhow::Result<()> {
592 let me = PublicKey::from_privkey(&PEERS_PRIVS[0]).unwrap().to_address();
593 let (cg, peer_addrs) = create_graph_and_resolver_entries(me);
594 let resolver = TestResolver(peer_addrs.clone());
595 let (peers, addrs) = make_address_pairs(peer_addrs);
596
597 let (p, cp) = TransportPath::resolve(vec![peers[1], peers[2], peers[3], peers[4]], &resolver, &cg).await?;
599 assert_eq!(4, p.length(), "must have 4 entries");
600 assert!(!p.contains_cycle(), "transport path must not contain a cycle");
601
602 let cp = cp.context("must have channel path")?;
603 assert_eq!(3, cp.length(), "channel path must be two hop");
604 assert_eq!(
605 vec![addrs[1], addrs[2], addrs[3]],
606 cp.hops(),
607 "channel path address must match"
608 );
609 assert!(!cp.contains_cycle(), "channel path must not contain a cycle");
610 Ok(())
611 }
612
613 #[async_std::test]
614 async fn test_transport_path_resolve_with_cycle() -> anyhow::Result<()> {
615 let me = PublicKey::from_privkey(&PEERS_PRIVS[0]).unwrap().to_address();
616 let (cg, peer_addrs) = create_graph_and_resolver_entries(me);
617 let resolver = TestResolver(peer_addrs.clone());
618 let (peers, addrs) = make_address_pairs(peer_addrs);
619
620 let (p, cp) = TransportPath::resolve(vec![peers[1], peers[2], peers[3], peers[1]], &resolver, &cg).await?;
622 assert_eq!(4, p.length(), "must have 4 entries");
623 assert!(p.contains_cycle(), "transport path must contain a cycle");
624
625 let cp = cp.context("must have channel path")?;
626 assert_eq!(3, cp.length(), "channel path must be 3 hop");
627 assert_eq!(
628 vec![addrs[1], addrs[2], addrs[3]],
629 cp.hops(),
630 "channel path address must match"
631 );
632 assert!(!cp.contains_cycle(), "channel path must not contain a cycle");
633 Ok(())
634 }
635
636 #[async_std::test]
637 async fn test_transport_path_resolve_with_channel_cycle() -> anyhow::Result<()> {
638 let me = PublicKey::from_privkey(&PEERS_PRIVS[0]).unwrap().to_address();
639 let (cg, peer_addrs) = create_graph_and_resolver_entries(me);
640 let resolver = TestResolver(peer_addrs.clone());
641 let (peers, addrs) = make_address_pairs(peer_addrs);
642
643 let (p, cp) =
645 TransportPath::resolve(vec![peers[1], peers[2], peers[3], peers[1], peers[2]], &resolver, &cg).await?;
646 assert_eq!(5, p.length(), "must be 5 hop");
647 assert!(p.contains_cycle(), "transport path must contain a cycle");
648
649 let cp = cp.context("must have channel path")?;
650 assert_eq!(4, cp.length(), "channel path must be 4 hop");
651 assert_eq!(
652 vec![addrs[1], addrs[2], addrs[3], addrs[1]],
653 cp.hops(),
654 "channel path address must match"
655 );
656 assert!(cp.contains_cycle(), "channel path must not contain a cycle");
657 Ok(())
658 }
659
660 #[async_std::test]
661 async fn test_transport_path_should_not_resolve_for_non_existing_intermediate_channel() -> anyhow::Result<()> {
662 let me = PublicKey::from_privkey(&PEERS_PRIVS[0]).unwrap().to_address();
663 let (cg, peer_addrs) = create_graph_and_resolver_entries(me);
664 let resolver = TestResolver(peer_addrs.clone());
665 let (peers, _) = make_address_pairs(peer_addrs);
666
667 TransportPath::resolve(vec![peers[2], peers[3]], &resolver, &cg)
669 .await
670 .expect_err("should not resolve path 1");
671
672 TransportPath::resolve(vec![peers[1], peers[3], peers[1]], &resolver, &cg)
674 .await
675 .expect_err("should not resolve path 2");
676 Ok(())
677 }
678
679 #[async_std::test]
680 async fn test_transport_path_should_not_resolve_for_non_open_intermediate_channel() -> anyhow::Result<()> {
681 let me = PublicKey::from_privkey(&PEERS_PRIVS[2]).unwrap().to_address();
682 let (cg, peer_addrs) = create_graph_and_resolver_entries(me);
683 let resolver = TestResolver(peer_addrs.clone());
684 let (peers, _) = make_address_pairs(peer_addrs);
685
686 TransportPath::resolve(vec![peers[3], peers[4], peers[0], peers[1]], &resolver, &cg)
688 .await
689 .expect_err("should not resolve path");
690 Ok(())
691 }
692
693 #[async_std::test]
694 async fn test_channel_path_to_transport_path() -> anyhow::Result<()> {
695 let me = PublicKey::from_privkey(&PEERS_PRIVS[0]).unwrap().to_address();
696 let (cg, peer_addrs) = create_graph_and_resolver_entries(me);
697 let resolver = TestResolver(peer_addrs.clone());
698 let (peers, addrs) = make_address_pairs(peer_addrs);
699
700 let cp = ChannelPath::new(vec![addrs[1], addrs[2], addrs[3]], &cg)?;
702
703 let tp = cp.clone().into_path(&resolver, addrs[4]).await?;
705 assert_eq!(
706 tp.length(),
707 cp.length() + 1,
708 "transport path must have extra hop to destination"
709 );
710 assert_eq!(
711 vec![peers[1], peers[2], peers[3], peers[4]],
712 tp.hops(),
713 "must contain all peer ids"
714 );
715 Ok(())
716 }
717}