1use std::str::FromStr;
19
20use sui_types::digests::{ChainIdentifier, CheckpointDigest};
21
22pub fn chain_id_base58(chain_id: &ChainIdentifier) -> String {
25 CheckpointDigest::new(*chain_id.as_bytes()).base58_encode()
26}
27
28pub fn chain_ids_match(a: &str, b: &str) -> bool {
33 match (decode_chain_id(a), decode_chain_id(b)) {
34 (Some(a), Some(b)) => {
35 let len = a.len().min(b.len());
36 a[..len] == b[..len]
37 }
38 _ => a == b,
39 }
40}
41
42fn decode_chain_id(s: &str) -> Option<Vec<u8>> {
45 if let Ok(digest) = CheckpointDigest::from_str(s) {
46 return Some(digest.inner().to_vec());
47 }
48
49 let hex = s.strip_prefix("0x").unwrap_or(s);
50 if hex.len() == 8 {
51 let bytes: Option<Vec<u8>> = (0..8)
52 .step_by(2)
53 .map(|i| u8::from_str_radix(&hex[i..i + 2], 16).ok())
54 .collect();
55 return bytes;
56 }
57
58 None
59}
60
61#[cfg(test)]
62mod tests {
63 use sui_types::digests::{
64 MAINNET_CHAIN_IDENTIFIER_BASE58, TESTNET_CHAIN_IDENTIFIER_BASE58,
65 get_mainnet_chain_identifier, get_testnet_chain_identifier,
66 };
67
68 use super::*;
69
70 const MAINNET_SHORT: &str = "35834a8a";
71 const TESTNET_SHORT: &str = "4c78adac";
72
73 #[test]
74 fn base58_form_of_known_chains() {
75 assert_eq!(
76 chain_id_base58(&get_mainnet_chain_identifier()),
77 MAINNET_CHAIN_IDENTIFIER_BASE58
78 );
79 assert_eq!(
80 chain_id_base58(&get_testnet_chain_identifier()),
81 TESTNET_CHAIN_IDENTIFIER_BASE58
82 );
83 }
84
85 #[test]
86 fn full_matches_full() {
87 assert!(chain_ids_match(
88 MAINNET_CHAIN_IDENTIFIER_BASE58,
89 MAINNET_CHAIN_IDENTIFIER_BASE58
90 ));
91 assert!(!chain_ids_match(
92 MAINNET_CHAIN_IDENTIFIER_BASE58,
93 TESTNET_CHAIN_IDENTIFIER_BASE58
94 ));
95 }
96
97 #[test]
98 fn short_matches_full_in_either_order() {
99 assert!(chain_ids_match(
100 MAINNET_SHORT,
101 MAINNET_CHAIN_IDENTIFIER_BASE58
102 ));
103 assert!(chain_ids_match(
104 MAINNET_CHAIN_IDENTIFIER_BASE58,
105 MAINNET_SHORT
106 ));
107 assert!(!chain_ids_match(
108 TESTNET_SHORT,
109 MAINNET_CHAIN_IDENTIFIER_BASE58
110 ));
111 }
112
113 #[test]
114 fn short_matches_short() {
115 assert!(chain_ids_match(MAINNET_SHORT, MAINNET_SHORT));
116 assert!(chain_ids_match(MAINNET_SHORT, "35834A8A"));
117 assert!(chain_ids_match("0x35834a8a", MAINNET_SHORT));
118 assert!(!chain_ids_match(MAINNET_SHORT, TESTNET_SHORT));
119 }
120
121 #[test]
122 fn opaque_ids_match_exactly() {
123 assert!(chain_ids_match("localnet", "localnet"));
124 assert!(!chain_ids_match("localnet", "Localnet"));
125 assert!(!chain_ids_match(
126 "localnet",
127 MAINNET_CHAIN_IDENTIFIER_BASE58
128 ));
129 }
130}