ibc_types_path/
lib.rs

1extern crate alloc;
2
3use alloc::string::{String, ToString};
4use alloc::vec::Vec;
5use ibc_types_core_client::Height;
6
7/// Path-space as listed in ICS-024
8/// https://github.com/cosmos/ibc/tree/master/spec/core/ics-024-host-requirements#path-space
9/// Some of these are implemented in other ICSs, but ICS-024 has a nice summary table.
10///
11use core::str::FromStr;
12
13use ibc_types_core_channel::{packet::Sequence, ChannelId, PortId};
14use ibc_types_core_client::ClientId;
15use ibc_types_core_connection::ConnectionId;
16
17use derive_more::{Display, From};
18
19/// ABCI Query path for the IBC sub-store
20pub const IBC_QUERY_PATH: &str = "store/ibc/key";
21
22/// ABCI Query path for the upgrade sub-store
23/// ## Note: This is SDK/Tenderminlightclients-tendermintt specific!
24pub const SDK_UPGRADE_QUERY_PATH: &str = "store/upgrade/key";
25
26/// ABCI client upgrade keys
27/// - The key identifying the upgraded IBC state within the upgrade sub-store
28const UPGRADED_IBC_STATE: &str = "upgradedIBCState";
29///- The key identifying the upgraded client state
30const UPGRADED_CLIENT_STATE: &str = "upgradedClient";
31/// - The key identifying the upgraded consensus state
32const UPGRADED_CLIENT_CONSENSUS_STATE: &str = "upgradedConsState";
33
34/// The Path enum abstracts out the different sub-paths.
35#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, From, Display)]
36pub enum Path {
37    ClientType(ClientTypePath),
38    ClientState(ClientStatePath),
39    ClientConsensusState(ClientConsensusStatePath),
40    ClientConnection(ClientConnectionPath),
41    Connection(ConnectionPath),
42    Ports(PortPath),
43    ChannelEnd(ChannelEndPath),
44    SeqSend(SeqSendPath),
45    SeqRecv(SeqRecvPath),
46    SeqAck(SeqAckPath),
47    Commitment(CommitmentPath),
48    Ack(AckPath),
49    Receipt(ReceiptPath),
50    Upgrade(ClientUpgradePath),
51}
52
53#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Display)]
54#[display(fmt = "clients/{_0}/clientType")]
55pub struct ClientTypePath(pub ClientId);
56
57impl ClientTypePath {
58    pub fn new(client_id: &ClientId) -> ClientTypePath {
59        ClientTypePath(client_id.clone())
60    }
61}
62
63#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Display)]
64#[display(fmt = "clients/{_0}/clientState")]
65pub struct ClientStatePath(pub ClientId);
66
67impl ClientStatePath {
68    pub fn new(client_id: &ClientId) -> ClientStatePath {
69        ClientStatePath(client_id.clone())
70    }
71}
72
73#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Display)]
74#[display(fmt = "clients/{client_id}/consensusStates/{epoch}-{height}")]
75pub struct ClientConsensusStatePath {
76    pub client_id: ClientId,
77    pub epoch: u64,
78    pub height: u64,
79}
80
81impl ClientConsensusStatePath {
82    pub fn new(client_id: &ClientId, height: &Height) -> ClientConsensusStatePath {
83        ClientConsensusStatePath {
84            client_id: client_id.clone(),
85            epoch: height.revision_number(),
86            height: height.revision_height(),
87        }
88    }
89}
90
91#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Display)]
92#[display(fmt = "clients/{_0}/connections")]
93pub struct ClientConnectionPath(pub ClientId);
94
95impl ClientConnectionPath {
96    pub fn new(client_id: &ClientId) -> ClientConnectionPath {
97        ClientConnectionPath(client_id.clone())
98    }
99}
100
101#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Display)]
102#[display(fmt = "connections/{_0}")]
103pub struct ConnectionPath(pub ConnectionId);
104
105impl ConnectionPath {
106    pub fn new(connection_id: &ConnectionId) -> ConnectionPath {
107        ConnectionPath(connection_id.clone())
108    }
109}
110
111#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Display)]
112#[display(fmt = "ports/{_0}")]
113pub struct PortPath(pub PortId);
114
115#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Display)]
116#[display(fmt = "channelEnds/ports/{_0}/channels/{_1}")]
117pub struct ChannelEndPath(pub PortId, pub ChannelId);
118
119impl ChannelEndPath {
120    pub fn new(port_id: &PortId, channel_id: &ChannelId) -> ChannelEndPath {
121        ChannelEndPath(port_id.clone(), channel_id.clone())
122    }
123}
124
125#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Display)]
126#[display(fmt = "nextSequenceSend/ports/{_0}/channels/{_1}")]
127pub struct SeqSendPath(pub PortId, pub ChannelId);
128
129impl SeqSendPath {
130    pub fn new(port_id: &PortId, channel_id: &ChannelId) -> SeqSendPath {
131        SeqSendPath(port_id.clone(), channel_id.clone())
132    }
133}
134
135#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Display)]
136#[display(fmt = "nextSequenceRecv/ports/{_0}/channels/{_1}")]
137pub struct SeqRecvPath(pub PortId, pub ChannelId);
138
139impl SeqRecvPath {
140    pub fn new(port_id: &PortId, channel_id: &ChannelId) -> SeqRecvPath {
141        SeqRecvPath(port_id.clone(), channel_id.clone())
142    }
143}
144
145#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Display)]
146#[display(fmt = "nextSequenceAck/ports/{_0}/channels/{_1}")]
147pub struct SeqAckPath(pub PortId, pub ChannelId);
148
149impl SeqAckPath {
150    pub fn new(port_id: &PortId, channel_id: &ChannelId) -> SeqAckPath {
151        SeqAckPath(port_id.clone(), channel_id.clone())
152    }
153}
154
155#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Display)]
156#[display(fmt = "commitments/ports/{port_id}/channels/{channel_id}/sequences/{sequence}")]
157pub struct CommitmentPath {
158    pub port_id: PortId,
159    pub channel_id: ChannelId,
160    pub sequence: Sequence,
161}
162
163impl CommitmentPath {
164    pub fn new(port_id: &PortId, channel_id: &ChannelId, sequence: Sequence) -> CommitmentPath {
165        CommitmentPath {
166            port_id: port_id.clone(),
167            channel_id: channel_id.clone(),
168            sequence,
169        }
170    }
171}
172
173#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Display)]
174#[display(fmt = "acks/ports/{port_id}/channels/{channel_id}/sequences/{sequence}")]
175pub struct AckPath {
176    pub port_id: PortId,
177    pub channel_id: ChannelId,
178    pub sequence: Sequence,
179}
180
181impl AckPath {
182    pub fn new(port_id: &PortId, channel_id: &ChannelId, sequence: Sequence) -> AckPath {
183        AckPath {
184            port_id: port_id.clone(),
185            channel_id: channel_id.clone(),
186            sequence,
187        }
188    }
189}
190
191#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Display)]
192#[display(fmt = "receipts/ports/{port_id}/channels/{channel_id}/sequences/{sequence}")]
193pub struct ReceiptPath {
194    pub port_id: PortId,
195    pub channel_id: ChannelId,
196    pub sequence: Sequence,
197}
198
199impl ReceiptPath {
200    pub fn new(port_id: &PortId, channel_id: &ChannelId, sequence: Sequence) -> ReceiptPath {
201        ReceiptPath {
202            port_id: port_id.clone(),
203            channel_id: channel_id.clone(),
204            sequence,
205        }
206    }
207}
208
209/// Paths that are specific for client upgrades.
210#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Display)]
211pub enum ClientUpgradePath {
212    #[display(fmt = "{UPGRADED_IBC_STATE}/{_0}/{UPGRADED_CLIENT_STATE}")]
213    UpgradedClientState(u64),
214    #[display(fmt = "{UPGRADED_IBC_STATE}/{_0}/{UPGRADED_CLIENT_CONSENSUS_STATE}")]
215    UpgradedClientConsensusState(u64),
216}
217
218/// Sub-paths which are not part of the specification, but are still
219/// useful to represent for parsing purposes.
220#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
221enum SubPath {
222    Channels(ChannelId),
223    Sequences(Sequence),
224}
225
226impl Path {
227    /// Indication if the path is provable.
228    pub fn is_provable(&self) -> bool {
229        !matches!(&self, Path::ClientConnection(_) | Path::Ports(_))
230    }
231
232    /// into_bytes implementation
233    pub fn into_bytes(self) -> Vec<u8> {
234        self.to_string().into_bytes()
235    }
236}
237
238#[derive(Debug, displaydoc::Display)]
239pub enum PathError {
240    /// `{path}` could not be parsed into a Path
241    ParseFailure { path: String },
242}
243
244#[cfg(feature = "std")]
245impl std::error::Error for PathError {}
246
247/// The FromStr trait allows paths encoded as strings to be parsed into Paths.
248impl FromStr for Path {
249    type Err = PathError;
250
251    fn from_str(s: &str) -> Result<Self, Self::Err> {
252        let components: Vec<&str> = s.split('/').collect();
253
254        parse_client_paths(&components)
255            .or_else(|| parse_connections(&components))
256            .or_else(|| parse_ports(&components))
257            .or_else(|| parse_channel_ends(&components))
258            .or_else(|| parse_seqs(&components))
259            .or_else(|| parse_commitments(&components))
260            .or_else(|| parse_acks(&components))
261            .or_else(|| parse_receipts(&components))
262            .or_else(|| parse_upgrades(&components))
263            .ok_or(PathError::ParseFailure {
264                path: s.to_string(),
265            })
266    }
267}
268
269fn parse_client_paths(components: &[&str]) -> Option<Path> {
270    let first = match components.first() {
271        Some(f) => *f,
272        None => return None,
273    };
274
275    if first != "clients" {
276        return None;
277    }
278
279    let client_id = match ClientId::from_str(components[1]) {
280        Ok(s) => s,
281        Err(_) => return None,
282    };
283
284    if components.len() == 3 {
285        match components[2] {
286            "clientType" => Some(ClientTypePath(client_id).into()),
287            "clientState" => Some(ClientStatePath(client_id).into()),
288            "connections" => Some(ClientConnectionPath(client_id).into()),
289            _ => None,
290        }
291    } else if components.len() == 4 {
292        if "consensusStates" != components[2] {
293            return None;
294        }
295
296        let epoch_height = match components.last() {
297            Some(eh) => *eh,
298            None => return None,
299        };
300
301        let epoch_height: Vec<&str> = epoch_height.split('-').collect();
302
303        if epoch_height.len() != 2 {
304            return None;
305        }
306
307        let epoch = epoch_height[0];
308        let height = epoch_height[1];
309
310        let epoch = match epoch.parse::<u64>() {
311            Ok(ep) => ep,
312            Err(_) => return None,
313        };
314
315        let height = match height.parse::<u64>() {
316            Ok(h) => h,
317            Err(_) => return None,
318        };
319
320        Some(
321            ClientConsensusStatePath {
322                client_id,
323                epoch,
324                height,
325            }
326            .into(),
327        )
328    } else {
329        None
330    }
331}
332
333fn parse_connections(components: &[&str]) -> Option<Path> {
334    if components.len() != 2 {
335        return None;
336    }
337
338    let first = match components.first() {
339        Some(f) => *f,
340        None => return None,
341    };
342
343    if first != "connections" {
344        return None;
345    }
346
347    let connection_id = match components.last() {
348        Some(c) => *c,
349        None => return None,
350    };
351
352    let connection_id = match ConnectionId::from_str(connection_id) {
353        Ok(c) => c,
354        Err(_) => return None,
355    };
356
357    Some(ConnectionPath(connection_id).into())
358}
359
360fn parse_ports(components: &[&str]) -> Option<Path> {
361    if components.len() != 2 {
362        return None;
363    }
364
365    let first = match components.first() {
366        Some(f) => *f,
367        None => return None,
368    };
369
370    if first != "ports" {
371        return None;
372    }
373
374    let port_id = match components.last() {
375        Some(p) => *p,
376        None => return None,
377    };
378
379    let port_id = match PortId::from_str(port_id) {
380        Ok(p) => p,
381        Err(_) => return None,
382    };
383
384    Some(PortPath(port_id).into())
385}
386
387fn parse_channels(components: &[&str]) -> Option<SubPath> {
388    if components.len() != 2 {
389        return None;
390    }
391
392    let first = match components.first() {
393        Some(f) => *f,
394        None => return None,
395    };
396
397    if first != "channels" {
398        return None;
399    }
400
401    let channel_id = match components.last() {
402        Some(c) => *c,
403        None => return None,
404    };
405
406    let channel_id = match ChannelId::from_str(channel_id) {
407        Ok(c) => c,
408        Err(_) => return None,
409    };
410
411    Some(SubPath::Channels(channel_id))
412}
413
414fn parse_sequences(components: &[&str]) -> Option<SubPath> {
415    if components.len() != 2 {
416        return None;
417    }
418
419    let first = match components.first() {
420        Some(f) => *f,
421        None => return None,
422    };
423
424    if first != "sequences" {
425        return None;
426    }
427
428    let sequence_number = match components.last() {
429        Some(s) => *s,
430        None => return None,
431    };
432
433    match Sequence::from_str(sequence_number) {
434        Ok(seq) => Some(SubPath::Sequences(seq)),
435        Err(_) => None,
436    }
437}
438
439fn parse_channel_ends(components: &[&str]) -> Option<Path> {
440    if components.len() != 5 {
441        return None;
442    }
443
444    let first = match components.first() {
445        Some(f) => *f,
446        None => return None,
447    };
448
449    if first != "channelEnds" {
450        return None;
451    }
452
453    let port = parse_ports(&components[1..=2]);
454    let channel = parse_channels(&components[3..=4]);
455
456    let port_id = if let Some(Path::Ports(PortPath(port_id))) = port {
457        port_id
458    } else {
459        return None;
460    };
461
462    let channel_id = if let Some(SubPath::Channels(channel_id)) = channel {
463        channel_id
464    } else {
465        return None;
466    };
467
468    Some(ChannelEndPath(port_id, channel_id).into())
469}
470
471fn parse_seqs(components: &[&str]) -> Option<Path> {
472    if components.len() != 5 {
473        return None;
474    }
475
476    let first = match components.first() {
477        Some(f) => *f,
478        None => return None,
479    };
480
481    let port = parse_ports(&components[1..=2]);
482    let channel = parse_channels(&components[3..=4]);
483
484    let port_id = if let Some(Path::Ports(PortPath(port_id))) = port {
485        port_id
486    } else {
487        return None;
488    };
489
490    let channel_id = if let Some(SubPath::Channels(channel_id)) = channel {
491        channel_id
492    } else {
493        return None;
494    };
495
496    match first {
497        "nextSequenceSend" => Some(SeqSendPath(port_id, channel_id).into()),
498        "nextSequenceRecv" => Some(SeqRecvPath(port_id, channel_id).into()),
499        "nextSequenceAck" => Some(SeqAckPath(port_id, channel_id).into()),
500        _ => None,
501    }
502}
503
504fn parse_commitments(components: &[&str]) -> Option<Path> {
505    if components.len() != 7 {
506        return None;
507    }
508
509    let first = match components.first() {
510        Some(f) => *f,
511        None => return None,
512    };
513
514    if first != "commitments" {
515        return None;
516    }
517
518    let port = parse_ports(&components[1..=2]);
519    let channel = parse_channels(&components[3..=4]);
520    let sequence = parse_sequences(&components[5..]);
521
522    let port_id = if let Some(Path::Ports(PortPath(port_id))) = port {
523        port_id
524    } else {
525        return None;
526    };
527
528    let channel_id = if let Some(SubPath::Channels(channel_id)) = channel {
529        channel_id
530    } else {
531        return None;
532    };
533
534    let sequence = if let Some(SubPath::Sequences(seq)) = sequence {
535        seq
536    } else {
537        return None;
538    };
539
540    Some(
541        CommitmentPath {
542            port_id,
543            channel_id,
544            sequence,
545        }
546        .into(),
547    )
548}
549
550fn parse_acks(components: &[&str]) -> Option<Path> {
551    if components.len() != 7 {
552        return None;
553    }
554
555    let first = match components.first() {
556        Some(f) => *f,
557        None => return None,
558    };
559
560    if first != "acks" {
561        return None;
562    }
563
564    let port = parse_ports(&components[1..=2]);
565    let channel = parse_channels(&components[3..=4]);
566    let sequence = parse_sequences(&components[5..]);
567
568    let port_id = if let Some(Path::Ports(PortPath(port_id))) = port {
569        port_id
570    } else {
571        return None;
572    };
573
574    let channel_id = if let Some(SubPath::Channels(channel_id)) = channel {
575        channel_id
576    } else {
577        return None;
578    };
579
580    let sequence = if let Some(SubPath::Sequences(seq)) = sequence {
581        seq
582    } else {
583        return None;
584    };
585
586    Some(
587        AckPath {
588            port_id,
589            channel_id,
590            sequence,
591        }
592        .into(),
593    )
594}
595
596fn parse_receipts(components: &[&str]) -> Option<Path> {
597    if components.len() != 7 {
598        return None;
599    }
600
601    let first = match components.first() {
602        Some(f) => *f,
603        None => return None,
604    };
605
606    if first != "receipts" {
607        return None;
608    }
609
610    let port = parse_ports(&components[1..=2]);
611    let channel = parse_channels(&components[3..=4]);
612    let sequence = parse_sequences(&components[5..]);
613
614    let port_id = if let Some(Path::Ports(PortPath(port_id))) = port {
615        port_id
616    } else {
617        return None;
618    };
619
620    let channel_id = if let Some(SubPath::Channels(channel_id)) = channel {
621        channel_id
622    } else {
623        return None;
624    };
625
626    let sequence = if let Some(SubPath::Sequences(seq)) = sequence {
627        seq
628    } else {
629        return None;
630    };
631
632    Some(
633        ReceiptPath {
634            port_id,
635            channel_id,
636            sequence,
637        }
638        .into(),
639    )
640}
641
642fn parse_upgrades(components: &[&str]) -> Option<Path> {
643    if components.len() != 3 {
644        return None;
645    }
646
647    let first = match components.first() {
648        Some(f) => *f,
649        None => return None,
650    };
651
652    if first != UPGRADED_IBC_STATE {
653        return None;
654    }
655
656    let last = match components.last() {
657        Some(l) => *l,
658        None => return None,
659    };
660
661    let height = match components[1].parse::<u64>() {
662        Ok(h) => h,
663        Err(_) => return None,
664    };
665
666    match last {
667        UPGRADED_CLIENT_STATE => Some(ClientUpgradePath::UpgradedClientState(height).into()),
668        UPGRADED_CLIENT_CONSENSUS_STATE => {
669            Some(ClientUpgradePath::UpgradedClientConsensusState(height).into())
670        }
671        _ => None,
672    }
673}
674
675#[cfg(test)]
676mod tests {
677    use super::*;
678    use core::str::FromStr;
679
680    #[test]
681    fn invalid_path_doesnt_parse() {
682        let invalid_path = Path::from_str("clients/clientType");
683
684        assert!(invalid_path.is_err());
685    }
686
687    #[test]
688    fn test_parse_client_paths_fn() {
689        let path = "clients/07-tendermint-0/clientType";
690        let components: Vec<&str> = path.split('/').collect();
691
692        assert_eq!(
693            parse_client_paths(&components),
694            Some(Path::ClientType(ClientTypePath(ClientId::default())))
695        );
696
697        let path = "clients/07-tendermint-0/clientState";
698        let components: Vec<&str> = path.split('/').collect();
699
700        assert_eq!(
701            parse_client_paths(&components),
702            Some(Path::ClientState(ClientStatePath(ClientId::default())))
703        );
704
705        let path = "clients/07-tendermint-0/consensusStates/15-31";
706        let components: Vec<&str> = path.split('/').collect();
707
708        assert_eq!(
709            parse_client_paths(&components),
710            Some(Path::ClientConsensusState(ClientConsensusStatePath {
711                client_id: ClientId::default(),
712                epoch: 15,
713                height: 31,
714            }))
715        );
716    }
717
718    #[test]
719    fn client_type_path_parses() {
720        let path = "clients/07-tendermint-0/clientType";
721        let path = Path::from_str(path);
722
723        assert!(path.is_ok());
724        assert_eq!(
725            path.unwrap(),
726            Path::ClientType(ClientTypePath(ClientId::default()))
727        );
728    }
729
730    #[test]
731    fn client_state_path_parses() {
732        let path = "clients/07-tendermint-0/clientState";
733        let path = Path::from_str(path);
734
735        assert!(path.is_ok());
736        assert_eq!(
737            path.unwrap(),
738            Path::ClientState(ClientStatePath(ClientId::default()))
739        );
740    }
741
742    #[test]
743    fn client_consensus_state_path_parses() {
744        let path = "clients/07-tendermint-0/consensusStates/15-31";
745        let path = Path::from_str(path);
746
747        assert!(path.is_ok());
748        assert_eq!(
749            path.unwrap(),
750            Path::ClientConsensusState(ClientConsensusStatePath {
751                client_id: ClientId::default(),
752                epoch: 15,
753                height: 31,
754            })
755        );
756    }
757
758    #[test]
759    fn client_connections_path_parses() {
760        let path = "clients/07-tendermint-0/connections";
761        let path = Path::from_str(path);
762
763        assert!(path.is_ok());
764        assert_eq!(
765            path.unwrap(),
766            Path::ClientConnection(ClientConnectionPath(ClientId::default()))
767        );
768    }
769
770    #[test]
771    fn test_parse_connections_fn() {
772        let path = "connections/connection-0";
773        let components: Vec<&str> = path.split('/').collect();
774
775        assert_eq!(
776            parse_connections(&components),
777            Some(Path::Connection(ConnectionPath(ConnectionId::new(0)))),
778        );
779    }
780
781    #[test]
782    fn connections_path_parses() {
783        let path = "connections/connection-0";
784        let path = Path::from_str(path);
785
786        assert!(path.is_ok());
787        assert_eq!(
788            path.unwrap(),
789            Path::Connection(ConnectionPath(ConnectionId::new(0)))
790        );
791    }
792
793    #[test]
794    fn test_parse_ports_fn() {
795        let path = "ports/defaultPort";
796        let components: Vec<&str> = path.split('/').collect();
797
798        assert_eq!(
799            parse_ports(&components),
800            Some(Path::Ports(PortPath(PortId::default()))),
801        );
802    }
803
804    #[test]
805    fn ports_path_parses() {
806        let path = "ports/defaultPort";
807        let path = Path::from_str(path);
808
809        assert!(path.is_ok());
810        assert_eq!(path.unwrap(), Path::Ports(PortPath(PortId::default())));
811    }
812
813    #[test]
814    fn test_parse_channels_fn() {
815        let path = "channels/channel-0";
816        let components: Vec<&str> = path.split('/').collect();
817
818        assert_eq!(
819            parse_channels(&components),
820            Some(SubPath::Channels(ChannelId::default())),
821        );
822    }
823
824    #[test]
825    fn channels_path_doesnt_parse() {
826        let path = "channels/channel-0";
827        let path = Path::from_str(path);
828
829        assert!(path.is_err());
830    }
831
832    #[test]
833    fn test_parse_sequences_fn() {
834        let path = "sequences/0";
835        let components: Vec<&str> = path.split('/').collect();
836
837        assert_eq!(
838            parse_sequences(&components),
839            Some(SubPath::Sequences(Sequence::default()))
840        );
841    }
842
843    #[test]
844    fn sequences_path_doesnt_parse() {
845        let path = "sequences/0";
846        let path = Path::from_str(path);
847
848        assert!(path.is_err());
849    }
850
851    #[test]
852    fn test_parse_channel_ends_fn() {
853        let path = "channelEnds/ports/defaultPort/channels/channel-0";
854        let components: Vec<&str> = path.split('/').collect();
855
856        assert_eq!(
857            parse_channel_ends(&components),
858            Some(Path::ChannelEnd(ChannelEndPath(
859                PortId::default(),
860                ChannelId::default()
861            ))),
862        );
863    }
864
865    #[test]
866    fn channel_ends_path_parses() {
867        let path = "channelEnds/ports/defaultPort/channels/channel-0";
868        let path = Path::from_str(path);
869
870        assert!(path.is_ok());
871        assert_eq!(
872            path.unwrap(),
873            Path::ChannelEnd(ChannelEndPath(PortId::default(), ChannelId::default())),
874        );
875    }
876
877    #[test]
878    fn test_parse_seqs_fn() {
879        let path = "nextSequenceSend/ports/defaultPort/channels/channel-0";
880        let components: Vec<&str> = path.split('/').collect();
881
882        assert_eq!(
883            parse_seqs(&components),
884            Some(Path::SeqSend(SeqSendPath(
885                PortId::default(),
886                ChannelId::default()
887            ))),
888        );
889
890        let path = "nextSequenceRecv/ports/defaultPort/channels/channel-0";
891        let components: Vec<&str> = path.split('/').collect();
892
893        assert_eq!(
894            parse_seqs(&components),
895            Some(Path::SeqRecv(SeqRecvPath(
896                PortId::default(),
897                ChannelId::default()
898            ))),
899        );
900
901        let path = "nextSequenceAck/ports/defaultPort/channels/channel-0";
902        let components: Vec<&str> = path.split('/').collect();
903
904        assert_eq!(
905            parse_seqs(&components),
906            Some(Path::SeqAck(SeqAckPath(
907                PortId::default(),
908                ChannelId::default()
909            ))),
910        );
911    }
912
913    #[test]
914    fn sequence_send_path_parses() {
915        let path = "nextSequenceSend/ports/defaultPort/channels/channel-0";
916        let path = Path::from_str(path);
917
918        assert!(path.is_ok());
919        assert_eq!(
920            path.unwrap(),
921            Path::SeqSend(SeqSendPath(PortId::default(), ChannelId::default())),
922        );
923    }
924
925    #[test]
926    fn sequence_recv_path_parses() {
927        let path = "nextSequenceRecv/ports/defaultPort/channels/channel-0";
928        let path = Path::from_str(path);
929
930        assert!(path.is_ok());
931        assert_eq!(
932            path.unwrap(),
933            Path::SeqRecv(SeqRecvPath(PortId::default(), ChannelId::default())),
934        );
935    }
936
937    #[test]
938    fn sequence_ack_path_parses() {
939        let path = "nextSequenceAck/ports/defaultPort/channels/channel-0";
940        let path = Path::from_str(path);
941
942        assert!(path.is_ok());
943        assert_eq!(
944            path.unwrap(),
945            Path::SeqAck(SeqAckPath(PortId::default(), ChannelId::default())),
946        );
947    }
948
949    #[test]
950    fn test_parse_commitments_fn() {
951        let path = "commitments/ports/defaultPort/channels/channel-0/sequences/0";
952        let components: Vec<&str> = path.split('/').collect();
953
954        assert_eq!(
955            parse_commitments(&components),
956            Some(Path::Commitment(CommitmentPath {
957                port_id: PortId::default(),
958                channel_id: ChannelId::default(),
959                sequence: Sequence::default(),
960            })),
961        );
962    }
963
964    #[test]
965    fn commitments_path_parses() {
966        let path = "commitments/ports/defaultPort/channels/channel-0/sequences/0";
967        let path = Path::from_str(path);
968
969        assert!(path.is_ok());
970        assert_eq!(
971            path.unwrap(),
972            Path::Commitment(CommitmentPath {
973                port_id: PortId::default(),
974                channel_id: ChannelId::default(),
975                sequence: Sequence::default(),
976            }),
977        );
978    }
979
980    #[test]
981    fn test_parse_acks_fn() {
982        let path = "acks/ports/defaultPort/channels/channel-0/sequences/0";
983        let components: Vec<&str> = path.split('/').collect();
984
985        assert_eq!(
986            parse_acks(&components),
987            Some(Path::Ack(AckPath {
988                port_id: PortId::default(),
989                channel_id: ChannelId::default(),
990                sequence: Sequence::default(),
991            })),
992        );
993    }
994
995    #[test]
996    fn acks_path_parses() {
997        let path = "acks/ports/defaultPort/channels/channel-0/sequences/0";
998        let path = Path::from_str(path);
999
1000        assert!(path.is_ok());
1001        assert_eq!(
1002            path.unwrap(),
1003            Path::Ack(AckPath {
1004                port_id: PortId::default(),
1005                channel_id: ChannelId::default(),
1006                sequence: Sequence::default(),
1007            }),
1008        );
1009    }
1010
1011    #[test]
1012    fn test_parse_receipts_fn() {
1013        let path = "receipts/ports/defaultPort/channels/channel-0/sequences/0";
1014        let components: Vec<&str> = path.split('/').collect();
1015
1016        assert_eq!(
1017            parse_receipts(&components),
1018            Some(Path::Receipt(ReceiptPath {
1019                port_id: PortId::default(),
1020                channel_id: ChannelId::default(),
1021                sequence: Sequence::default(),
1022            })),
1023        );
1024    }
1025
1026    #[test]
1027    fn receipts_path_parses() {
1028        let path = "receipts/ports/defaultPort/channels/channel-0/sequences/0";
1029        let path = Path::from_str(path);
1030
1031        assert!(path.is_ok());
1032        assert_eq!(
1033            path.unwrap(),
1034            Path::Receipt(ReceiptPath {
1035                port_id: PortId::default(),
1036                channel_id: ChannelId::default(),
1037                sequence: Sequence::default(),
1038            }),
1039        );
1040    }
1041
1042    #[test]
1043    fn test_parse_upgrades_fn() {
1044        let path = "upgradedIBCState/0/upgradedClient";
1045        let components: Vec<&str> = path.split('/').collect();
1046
1047        assert_eq!(
1048            parse_upgrades(&components),
1049            Some(Path::Upgrade(ClientUpgradePath::UpgradedClientState(0))),
1050        );
1051
1052        let path = "upgradedIBCState/0/upgradedConsState";
1053        let components: Vec<&str> = path.split('/').collect();
1054
1055        assert_eq!(
1056            parse_upgrades(&components),
1057            Some(Path::Upgrade(
1058                ClientUpgradePath::UpgradedClientConsensusState(0)
1059            )),
1060        )
1061    }
1062
1063    #[test]
1064    fn upgrade_client_state_path_parses() {
1065        let path = "upgradedIBCState/0/upgradedClient";
1066        let path = Path::from_str(path);
1067
1068        assert!(path.is_ok());
1069        assert_eq!(
1070            path.unwrap(),
1071            Path::Upgrade(ClientUpgradePath::UpgradedClientState(0)),
1072        );
1073    }
1074
1075    #[test]
1076    fn upgrade_client_consensus_state_path_parses() {
1077        let path = "upgradedIBCState/0/upgradedConsState";
1078        let path = Path::from_str(path);
1079
1080        assert!(path.is_ok());
1081        assert_eq!(
1082            path.unwrap(),
1083            Path::Upgrade(ClientUpgradePath::UpgradedClientConsensusState(0)),
1084        );
1085    }
1086}