common_primitives/
utils.rs

1extern crate alloc;
2use alloc::vec::Vec;
3
4/// Mainnet Genesis Hash 0x4a587bf17a404e3572747add7aab7bbe56e805a5479c6c436f07f36fcc8d3ae1
5pub const MAINNET_GENESIS_HASH: &[u8] = &[
6	74u8, 88, 123, 241, 122, 64, 78, 53, 114, 116, 122, 221, 122, 171, 123, 190, 86, 232, 5, 165,
7	71, 156, 108, 67, 111, 7, 243, 111, 204, 141, 58, 225,
8];
9
10/// Frequency Testnet on Paseo Genesis Hash 0x203c6838fc78ea3660a2f298a58d859519c72a5efdc0f194abd6f0d5ce1838e0
11pub const TESTNET_ON_PASEO_GENESIS_HASH: &[u8] = &[
12	32, 60, 104, 56, 252, 120, 234, 54, 96, 162, 242, 152, 165, 141, 133, 149, 25, 199, 42, 94,
13	253, 192, 241, 148, 171, 214, 240, 213, 206, 24, 56, 224,
14];
15
16/// Frequency Testnet on Westend Genesis Hash 0xe143f23803ac50e8f6f8e62695d1ce9e4e1d68aa36c1cd2cfd15340213f3423e
17pub const TESTNET_ON_WESTEND_GENESIS_HASH: &[u8] = &[
18	225, 67, 242, 56, 3, 172, 80, 232, 246, 248, 230, 38, 149, 209, 206, 158, 78, 29, 104, 170, 54,
19	193, 205, 44, 253, 21, 52, 2, 19, 243, 66, 62,
20];
21
22/// An enum that shows the detected chain type
23#[derive(Debug, Clone, PartialEq)]
24pub enum DetectedChainType {
25	/// An unknown chain, it can be a local or development chain
26	Unknown,
27	/// Frequency Mainnet
28	FrequencyMainNet,
29	/// Frequency Paseo Testnet
30	FrequencyPaseoTestNet,
31	/// Frequency Westend Testnet
32	FrequencyWestendTestNet,
33}
34
35/// Finds the chain type by genesis hash
36pub fn get_chain_type_by_genesis_hash(genesis_hash: &[u8]) -> DetectedChainType {
37	match genesis_hash {
38		MAINNET_GENESIS_HASH => DetectedChainType::FrequencyMainNet,
39		TESTNET_ON_PASEO_GENESIS_HASH => DetectedChainType::FrequencyPaseoTestNet,
40		TESTNET_ON_WESTEND_GENESIS_HASH => DetectedChainType::FrequencyWestendTestNet,
41		_ => DetectedChainType::Unknown,
42	}
43}
44
45/// Generic function for converting any unsigned integer to a 32-byte array compatible with ETH abi
46pub fn to_abi_compatible_number<T: Into<u128>>(value: T) -> [u8; 32] {
47	let value_u128: u128 = value.into();
48	let bytes = value_u128.to_be_bytes();
49	let start_idx = 32 - bytes.len();
50	let mut result = [0u8; 32];
51	result[start_idx..].copy_from_slice(&bytes);
52	result
53}
54
55/// Handle serializing and deserializing from `Vec<u8>` to hexadecimal
56#[cfg(feature = "std")]
57pub mod as_hex {
58	use serde::{Deserializer, Serializer};
59
60	/// Serializes a `Vec<u8>` into a hexadecimal string
61	pub fn serialize<S>(bytes: &Vec<u8>, serializer: S) -> Result<S::Ok, S::Error>
62	where
63		S: Serializer,
64	{
65		impl_serde::serialize::serialize(bytes.as_slice(), serializer)
66	}
67
68	/// Deserializes a hexadecimal string into a `Vec<u8>`
69	pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Vec<u8>, D::Error> {
70		impl_serde::serialize::deserialize(deserializer)
71	}
72}
73
74/// Handle serializing and deserializing from `Option<Vec<u8>>` to hexadecimal
75#[cfg(feature = "std")]
76pub mod as_hex_option {
77	use serde::{Deserializer, Serializer};
78
79	/// Serializes a `Vec<u8>` into a hexadecimal string
80	pub fn serialize<S>(bytes: &Option<Vec<u8>>, serializer: S) -> Result<S::Ok, S::Error>
81	where
82		S: Serializer,
83	{
84		match bytes {
85			Some(bytes) => impl_serde::serialize::serialize(bytes.as_slice(), serializer),
86			None => serializer.serialize_none(),
87		}
88	}
89
90	/// Deserializes a hexadecimal string into a `Vec<u8>`
91	pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<Vec<u8>>, D::Error>
92	where
93		D: Deserializer<'de>,
94	{
95		impl_serde::serialize::deserialize(deserializer).map(Some)
96	}
97}
98/// Handle serializing and deserializing from `Vec<u8>` to a UTF-8 string
99#[cfg(feature = "std")]
100pub mod as_string {
101	use super::*;
102	use serde::{ser::Error, Deserialize, Deserializer, Serialize, Serializer};
103
104	/// Serializes a `Vec<u8>` into a UTF-8 string
105	pub fn serialize<S: Serializer>(bytes: &[u8], serializer: S) -> Result<S::Ok, S::Error> {
106		std::str::from_utf8(bytes)
107			.map_err(|e| S::Error::custom(format!("Debug buffer contains invalid UTF8: {e:?}")))?
108			.serialize(serializer)
109	}
110
111	/// Serializes a UTF-8 string into a `Vec<u8>`
112	pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Vec<u8>, D::Error> {
113		Ok(String::deserialize(deserializer)?.into_bytes())
114	}
115}
116
117/// Handle serializing and deserializing from `Option<Vec<u8>>` to a UTF-8 string
118#[cfg(feature = "std")]
119pub mod as_string_option {
120	use super::*;
121	use serde::{ser::Error, Deserialize, Deserializer, Serialize, Serializer};
122
123	/// Serializes a `Option<Vec<u8>>` into a UTF-8 string if Ok()
124	pub fn serialize<S: Serializer>(
125		bytes: &Option<Vec<u8>>,
126		serializer: S,
127	) -> Result<S::Ok, S::Error> {
128		match bytes {
129			Some(bytes) => std::str::from_utf8(bytes)
130				.map_err(|e| {
131					S::Error::custom(format!("Debug buffer contains invalid UTF8: {e:?}"))
132				})?
133				.serialize(serializer),
134			None => serializer.serialize_none(),
135		}
136	}
137
138	/// Deserializes a UTF-8 string into a `Option<Vec<u8>>`
139	pub fn deserialize<'de, D: Deserializer<'de>>(
140		deserializer: D,
141	) -> Result<Option<Vec<u8>>, D::Error> {
142		let bytes = String::deserialize(deserializer)?.into_bytes();
143		Ok(match bytes.len() {
144			0 => None,
145			_ => Some(bytes),
146		})
147	}
148}
149
150const PREFIX: &str = "<Bytes>";
151const POSTFIX: &str = "</Bytes>";
152
153/// Wraps `PREFIX` and `POSTFIX` around a `Vec<u8>`
154/// Returns `PREFIX` ++ `data` ++ `POSTFIX`
155pub fn wrap_binary_data(data: Vec<u8>) -> Vec<u8> {
156	let mut encapsuled = PREFIX.as_bytes().to_vec();
157	encapsuled.append(&mut data.clone());
158	encapsuled.append(&mut POSTFIX.as_bytes().to_vec());
159	encapsuled
160}
161
162/// This is useful for testing and benchmarks and should not be used for any
163/// cryptographically secure operation
164#[cfg(any(test, feature = "runtime-benchmarks"))]
165pub struct XorRng {
166	state: u64,
167}
168
169#[cfg(any(test, feature = "runtime-benchmarks"))]
170impl XorRng {
171	/// Creates Rnd from the seed
172	pub fn new(seed: u64) -> Self {
173		Self { state: if seed == 0 { 1 } else { seed } }
174	}
175
176	/// Generates the next u8
177	pub fn gen_u8(&mut self) -> u8 {
178		// XorShift64
179		self.state ^= self.state << 13;
180		self.state ^= self.state >> 7;
181		self.state ^= self.state << 17;
182		self.state as u8
183	}
184}
185
186#[cfg(test)]
187mod tests {
188	use super::*;
189	use impl_serde::serialize::from_hex;
190	use parity_scale_codec::{Decode, Encode};
191	use scale_info::TypeInfo;
192	use serde::{Deserialize, Serialize};
193	use sp_core::U256;
194
195	#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
196	#[derive(Default, Clone, Encode, Decode, PartialEq, Debug, TypeInfo, Eq)]
197	struct TestAsHex {
198		#[cfg_attr(feature = "std", serde(with = "as_hex",))]
199		pub data: Vec<u8>,
200	}
201
202	#[test]
203	fn as_hex_can_serialize() {
204		let test_data = TestAsHex { data: vec![1, 2, 3, 4] };
205		let result = serde_json::to_string(&test_data);
206		assert!(result.is_ok());
207		assert_eq!("{\"data\":\"0x01020304\"}", result.unwrap());
208	}
209
210	#[test]
211	fn as_hex_can_deserialize() {
212		let result: Result<TestAsHex, serde_json::Error> =
213			serde_json::from_str("{\"data\":\"0x01020304\"}");
214		assert!(result.is_ok());
215		assert_eq!(vec![1, 2, 3, 4], result.unwrap().data);
216	}
217
218	#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
219	#[derive(Default, Clone, Encode, Decode, PartialEq, Debug, TypeInfo, Eq)]
220	struct TestAsHexOption {
221		#[cfg_attr(
222			feature = "std",
223			serde(with = "as_hex_option", skip_serializing_if = "Option::is_none", default)
224		)]
225		pub data: Option<Vec<u8>>,
226	}
227
228	#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
229	#[derive(Default, Clone, Encode, Decode, PartialEq, Debug, TypeInfo, Eq)]
230	struct TestAsHexOptionNull {
231		#[cfg_attr(feature = "std", serde(with = "as_hex_option", default))]
232		pub data: Option<Vec<u8>>,
233	}
234
235	#[test]
236	fn as_hex_option_can_serialize() {
237		let test_data = TestAsHexOption { data: Some(vec![1, 2, 3, 4]) };
238		let result = serde_json::to_string(&test_data);
239		assert!(result.is_ok());
240		assert_eq!("{\"data\":\"0x01020304\"}", result.unwrap());
241	}
242
243	#[test]
244	fn as_hex_option_can_deserialize() {
245		let result: Result<TestAsHexOption, serde_json::Error> =
246			serde_json::from_str("{\"data\":\"0x01020304\"}");
247		assert!(result.is_ok());
248		assert_eq!(Some(vec![1, 2, 3, 4]), result.unwrap().data);
249	}
250
251	#[test]
252	fn as_hex_option_can_serialize_nothing_with_skip() {
253		let test_data = TestAsHexOption { data: None };
254		let result = serde_json::to_string(&test_data);
255		assert!(result.is_ok());
256		assert_eq!("{}", result.unwrap());
257	}
258
259	#[test]
260	fn as_hex_option_can_serialize_nothing_as_null() {
261		let test_data = TestAsHexOptionNull { data: None };
262		let result = serde_json::to_string(&test_data);
263		assert!(result.is_ok());
264		assert_eq!("{\"data\":null}", result.unwrap());
265	}
266
267	#[test]
268	fn as_hex_option_can_deserialize_nothing() {
269		let result: Result<TestAsHexOption, serde_json::Error> = serde_json::from_str("{}");
270		assert!(result.is_ok());
271		assert_eq!(None, result.unwrap().data);
272	}
273
274	#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
275	#[derive(Default, Clone, Encode, Decode, PartialEq, Debug, TypeInfo, Eq)]
276	struct TestAsString {
277		#[cfg_attr(feature = "std", serde(with = "as_string"))]
278		pub data: Vec<u8>,
279	}
280
281	#[test]
282	fn as_string_can_serialize() {
283		let test_data = TestAsString {
284			data: vec![
285				0xe8, 0x95, 0x99, 0x49, 0xdd, 0x9d, 0xcd, 0x99, 0xe0, 0xbc, 0x8d, 0x4c, 0xd0, 0xbc,
286			],
287		};
288		let result = serde_json::to_string(&test_data);
289		assert!(result.is_ok());
290		assert_eq!("{\"data\":\"蕙Iݝ͙།Lм\"}", result.unwrap());
291	}
292
293	#[test]
294	fn as_string_can_deserialize() {
295		let result: Result<TestAsString, serde_json::Error> =
296			serde_json::from_str("{\"data\":\"蕙Iݝ͙།Lм\"}");
297		assert!(result.is_ok());
298		assert_eq!(
299			vec![
300				0xe8, 0x95, 0x99, 0x49, 0xdd, 0x9d, 0xcd, 0x99, 0xe0, 0xbc, 0x8d, 0x4c, 0xd0, 0xbc
301			],
302			result.unwrap().data
303		);
304	}
305
306	#[test]
307	fn as_string_errors_for_bad_utf8_vec() {
308		let test_data = TestAsString { data: vec![0xc3, 0x28] };
309		let result = serde_json::to_string(&test_data);
310		assert!(result.is_err());
311	}
312
313	#[test]
314	fn as_string_errors_for_bad_utf8_str() {
315		let result: Result<TestAsString, serde_json::Error> =
316			serde_json::from_str("{\"data\":\"\\xa0\\xa1\"}");
317		assert!(result.is_err());
318	}
319
320	#[test]
321	fn get_chain_type_by_genesis_hash_with_mainnet_genesis_should_get_mainnet() {
322		// arrange
323		let known_genesis =
324			from_hex("4a587bf17a404e3572747add7aab7bbe56e805a5479c6c436f07f36fcc8d3ae1").unwrap();
325
326		// act
327		let detected = get_chain_type_by_genesis_hash(&known_genesis);
328
329		// assert
330		assert_eq!(detected, DetectedChainType::FrequencyMainNet);
331	}
332
333	#[test]
334	fn get_chain_type_by_genesis_hash_with_paseo_genesis_should_get_paseo() {
335		// arrange
336		let known_genesis =
337			from_hex("203c6838fc78ea3660a2f298a58d859519c72a5efdc0f194abd6f0d5ce1838e0").unwrap();
338
339		// act
340		let detected = get_chain_type_by_genesis_hash(&known_genesis);
341
342		// assert
343		assert_eq!(detected, DetectedChainType::FrequencyPaseoTestNet);
344	}
345
346	#[test]
347	fn abi_compatible_number_should_work_with_different_types() {
348		// For u8
349		let u8_val: u8 = 42;
350		let coded_u8_val = to_abi_compatible_number(u8_val);
351		let u8_val: U256 = u8_val.into();
352		assert_eq!(
353			coded_u8_val.to_vec(),
354			sp_core::bytes::from_hex(&format!("0x{:064x}", u8_val)).unwrap()
355		);
356
357		// For u16
358		let u16_val: u16 = 12345;
359		let coded_u16_val = to_abi_compatible_number(u16_val);
360		let u16_val: U256 = u16_val.into();
361		assert_eq!(
362			coded_u16_val.to_vec(),
363			sp_core::bytes::from_hex(&format!("0x{:064x}", u16_val)).unwrap()
364		);
365
366		// For u32
367		let u32_val: u32 = 305419896;
368		let coded_u32_val = to_abi_compatible_number(u32_val);
369		let u32_val: U256 = u32_val.into();
370		assert_eq!(
371			coded_u32_val.to_vec(),
372			sp_core::bytes::from_hex(&format!("0x{:064x}", u32_val)).unwrap()
373		);
374
375		// For u64
376		let u64_val: u64 = 1234567890123456789;
377		let coded_u64_val = to_abi_compatible_number(u64_val);
378		let u64_val: U256 = u64_val.into();
379		assert_eq!(
380			coded_u64_val.to_vec(),
381			sp_core::bytes::from_hex(&format!("0x{:064x}", u64_val)).unwrap()
382		);
383
384		// For u128
385		let u128_val: u128 = 340282366920938463463374607431768211455; // Max u128 value
386		let coded_u128_val = to_abi_compatible_number(u128_val);
387		let u128_val: U256 = u128_val.into();
388		assert_eq!(
389			coded_u128_val.to_vec(),
390			sp_core::bytes::from_hex(&format!("0x{:064x}", u128_val)).unwrap()
391		);
392	}
393
394	#[test]
395	fn get_chain_type_by_genesis_hash_with_westend_genesis_should_get_westend() {
396		// arrange
397		let known_genesis =
398			from_hex("e143f23803ac50e8f6f8e62695d1ce9e4e1d68aa36c1cd2cfd15340213f3423e").unwrap();
399
400		// act
401		let detected = get_chain_type_by_genesis_hash(&known_genesis);
402
403		// assert
404		assert_eq!(detected, DetectedChainType::FrequencyWestendTestNet);
405	}
406}