avail_rust_core/
utils.rs

1use crate::{AccountId, AccountIdLike};
2use codec::{Decode, Encode};
3use sp_crypto_hashing::blake2_256;
4
5pub fn decode_already_decoded<I: codec::Input>(input: &mut I) -> Result<Vec<u8>, codec::Error> {
6	let length = input.remaining_len()?;
7	let Some(length) = length else {
8		return Err("Failed to decode transaction".into());
9	};
10	if length == 0 {
11		return Ok(Vec::new());
12	}
13	let mut value = vec![0u8; length];
14	input.read(&mut value)?;
15	Ok(value)
16}
17
18pub fn account_id_from_str(value: &str) -> Result<AccountId, String> {
19	if value.starts_with("0x") {
20		// Cannot be in SS58 format
21		let decoded = const_hex::decode(value.trim_start_matches("0x")).map_err(|e| e.to_string())?;
22		return account_id_from_slice(&decoded);
23	}
24
25	value.parse().map_err(|e| std::format!("{:?}", e))
26}
27
28pub fn account_id_from_slice(value: &[u8]) -> Result<AccountId, String> {
29	let account_id: [u8; 32] = match value.try_into() {
30		Ok(x) => x,
31		Err(err) => return Err(err.to_string()),
32	};
33
34	Ok(AccountId { 0: account_id })
35}
36
37/// Derive a multi-account ID from the sorted list of accounts and the threshold that are
38/// required.
39pub fn multi_account_id(who: &[impl Into<AccountIdLike> + Clone], threshold: u16) -> AccountId {
40	let who: Vec<AccountIdLike> = who.iter().map(|x| x.clone().into()).collect();
41	let mut who: Vec<AccountId> = who
42		.into_iter()
43		.map(|x| AccountId::try_from(x).expect("Malformed string is passed for AccountId"))
44		.collect();
45
46	who.sort();
47
48	let entropy = (b"modlpy/utilisuba", who, threshold).using_encoded(blake2_256);
49	Decode::decode(&mut TrailingZeroInput::new(entropy.as_ref()))
50		.expect("infinite length input; no invalid inputs for type; qed")
51}
52
53/// Input that adds infinite number of zero after wrapped input.
54struct TrailingZeroInput<'a>(&'a [u8]);
55
56impl<'a> TrailingZeroInput<'a> {
57	/// Create a new instance from the given byte array.
58	pub fn new(data: &'a [u8]) -> Self {
59		Self(data)
60	}
61
62	// Create a new instance which only contains zeroes as input.
63	// pub fn zeroes() -> Self {
64	// 	Self::new(&[][..])
65	// }
66}
67
68impl<'a> codec::Input for TrailingZeroInput<'a> {
69	fn remaining_len(&mut self) -> Result<Option<usize>, codec::Error> {
70		Ok(None)
71	}
72
73	fn read(&mut self, into: &mut [u8]) -> Result<(), codec::Error> {
74		let len_from_inner = into.len().min(self.0.len());
75		into[..len_from_inner].copy_from_slice(&self.0[..len_from_inner]);
76		for i in &mut into[len_from_inner..] {
77			*i = 0;
78		}
79		self.0 = &self.0[len_from_inner..];
80
81		Ok(())
82	}
83}