use crate::{
chain_api::{
entropy::{
self,
runtime_types::{
bounded_collections::bounded_vec::BoundedVec, pallet_programs::pallet::ProgramInfo,
},
},
EntropyConfig,
},
user::UserErr,
};
pub use entropy_client::substrate::{query_chain, submit_transaction};
use entropy_shared::user::ValidatorInfo;
use rand::prelude::SliceRandom;
use subxt::{backend::legacy::LegacyRpcMethods, utils::AccountId32, Config, OnlineClient};
pub async fn get_stash_address(
api: &OnlineClient<EntropyConfig>,
rpc: &LegacyRpcMethods<EntropyConfig>,
threshold_account_id: &AccountId32,
) -> Result<AccountId32, UserErr> {
let block_hash = rpc.chain_get_block_hash(None).await?;
let stash_address_query =
entropy::storage().staking_extension().threshold_to_stash(threshold_account_id);
let stash_address = query_chain(api, rpc, stash_address_query, block_hash)
.await?
.ok_or_else(|| UserErr::ChainFetch("Stash Fetch Error"))?;
Ok(stash_address)
}
pub async fn get_program(
api: &OnlineClient<EntropyConfig>,
rpc: &LegacyRpcMethods<EntropyConfig>,
program_pointer: &<EntropyConfig as Config>::Hash,
) -> Result<ProgramInfo, UserErr> {
let bytecode_address = entropy::storage().programs().programs(program_pointer);
let program_info = query_chain(api, rpc, bytecode_address, None)
.await?
.ok_or(UserErr::NoProgramDefined(program_pointer.to_string()))?;
Ok(program_info)
}
pub async fn get_oracle_data(
api: &OnlineClient<EntropyConfig>,
rpc: &LegacyRpcMethods<EntropyConfig>,
program_oracle_datas: Vec<Vec<u8>>,
) -> Result<Vec<Vec<u8>>, UserErr> {
let mut oracle_infos = vec![];
for program_oracle_data in program_oracle_datas {
let oracle_data_call =
entropy::storage().oracle().oracle_data(BoundedVec(program_oracle_data));
let oracle_info =
query_chain(api, rpc, oracle_data_call, None).await?.unwrap_or(BoundedVec(vec![]));
oracle_infos.push(oracle_info.0);
}
Ok(oracle_infos)
}
pub async fn get_validators_info(
api: &OnlineClient<EntropyConfig>,
rpc: &LegacyRpcMethods<EntropyConfig>,
validators: Vec<AccountId32>,
) -> Result<Vec<ValidatorInfo>, UserErr> {
let mut handles = Vec::new();
let block_hash = rpc.chain_get_block_hash(None).await?;
for validator in validators {
let handle: tokio::task::JoinHandle<Result<ValidatorInfo, UserErr>> = tokio::task::spawn({
let api = api.clone();
let rpc = rpc.clone();
async move {
let threshold_address_query =
entropy::storage().staking_extension().threshold_servers(validator);
let server_info = query_chain(&api, &rpc, threshold_address_query, block_hash)
.await?
.ok_or_else(|| {
UserErr::OptionUnwrapError("Failed to unwrap validator info".to_string())
})?;
Ok(ValidatorInfo {
x25519_public_key: server_info.x25519_public_key,
ip_address: std::str::from_utf8(&server_info.endpoint)?.to_string(),
tss_account: server_info.tss_account,
})
}
});
handles.push(handle);
}
let mut all_signers: Vec<ValidatorInfo> = vec![];
for handle in handles {
all_signers.push(handle.await.unwrap().unwrap());
}
Ok(all_signers)
}
pub async fn get_signers_from_chain(
api: &OnlineClient<EntropyConfig>,
rpc: &LegacyRpcMethods<EntropyConfig>,
) -> Result<(Vec<ValidatorInfo>, Vec<AccountId32>), UserErr> {
let signer_query = entropy::storage().staking_extension().signers();
let signers = query_chain(api, rpc, signer_query, None)
.await?
.ok_or_else(|| UserErr::ChainFetch("Get all validators error"))?;
let key_info_query = entropy::storage().parameters().signers_info();
let threshold = query_chain(api, rpc, key_info_query, None)
.await?
.ok_or_else(|| UserErr::ChainFetch("Failed to get signers info"))?
.threshold;
let selected_signers: Vec<_> = {
let cloned_signers = signers.clone();
cloned_signers
.choose_multiple(&mut rand::thread_rng(), threshold as usize)
.cloned()
.collect()
};
let block_hash = rpc.chain_get_block_hash(None).await?;
let mut handles = Vec::new();
for signer in selected_signers {
let handle: tokio::task::JoinHandle<Result<ValidatorInfo, UserErr>> = tokio::task::spawn({
let api = api.clone();
let rpc = rpc.clone();
async move {
let threshold_address_query =
entropy::storage().staking_extension().threshold_servers(signer);
let server_info = query_chain(&api, &rpc, threshold_address_query, block_hash)
.await?
.ok_or_else(|| UserErr::ChainFetch("threshold_servers query error"))?;
Ok(ValidatorInfo {
x25519_public_key: server_info.x25519_public_key,
ip_address: std::str::from_utf8(&server_info.endpoint)?.to_string(),
tss_account: server_info.tss_account,
})
}
});
handles.push(handle);
}
let mut all_selected_signers: Vec<ValidatorInfo> = vec![];
for handle in handles {
all_selected_signers.push(handle.await??);
}
Ok((all_selected_signers, signers))
}