use crate::{
error::{Error, Result},
AccountIdOf, AccountKeyPairOf, BlockNumberOf, Chain, ChainWithGrandpa, ChainWithTransactions,
HashOf, HeaderIdOf, HeaderOf, NonceOf, SignedBlockOf, SimpleRuntimeVersion, Subscription,
TransactionTracker, UnsignedTransaction,
};
use async_trait::async_trait;
use bp_runtime::{StorageDoubleMapKeyProvider, StorageMapKeyProvider};
use codec::{Decode, Encode};
use frame_support::weights::Weight;
use sp_core::{
storage::{StorageData, StorageKey},
Bytes, Pair,
};
use sp_runtime::{traits::Header as _, transaction_validity::TransactionValidity};
use sp_trie::StorageProof;
use sp_version::RuntimeVersion;
use std::fmt::Debug;
#[async_trait]
pub trait Client<C: Chain>: 'static + Send + Sync + Clone + Debug {
async fn ensure_synced(&self) -> Result<()>;
async fn reconnect(&self) -> Result<()>;
fn genesis_hash(&self) -> HashOf<C>;
async fn header_hash_by_number(&self, number: BlockNumberOf<C>) -> Result<HashOf<C>>;
async fn header_by_hash(&self, hash: HashOf<C>) -> Result<HeaderOf<C>>;
async fn header_by_number(&self, number: BlockNumberOf<C>) -> Result<HeaderOf<C>> {
self.header_by_hash(self.header_hash_by_number(number).await?).await
}
async fn block_by_hash(&self, hash: HashOf<C>) -> Result<SignedBlockOf<C>>;
async fn best_finalized_header_hash(&self) -> Result<HashOf<C>>;
async fn best_finalized_header_number(&self) -> Result<BlockNumberOf<C>> {
Ok(*self.best_finalized_header().await?.number())
}
async fn best_finalized_header(&self) -> Result<HeaderOf<C>> {
self.header_by_hash(self.best_finalized_header_hash().await?).await
}
async fn best_header(&self) -> Result<HeaderOf<C>>;
async fn best_header_hash(&self) -> Result<HashOf<C>> {
Ok(self.best_header().await?.hash())
}
async fn subscribe_best_headers(&self) -> Result<Subscription<HeaderOf<C>>>;
async fn subscribe_finalized_headers(&self) -> Result<Subscription<HeaderOf<C>>>;
async fn subscribe_grandpa_finality_justifications(&self) -> Result<Subscription<Bytes>>
where
C: ChainWithGrandpa;
async fn generate_grandpa_key_ownership_proof(
&self,
at: HashOf<C>,
set_id: sp_consensus_grandpa::SetId,
authority_id: sp_consensus_grandpa::AuthorityId,
) -> Result<Option<sp_consensus_grandpa::OpaqueKeyOwnershipProof>>;
async fn subscribe_beefy_finality_justifications(&self) -> Result<Subscription<Bytes>>;
async fn token_decimals(&self) -> Result<Option<u64>>;
async fn runtime_version(&self) -> Result<RuntimeVersion>;
async fn simple_runtime_version(&self) -> Result<SimpleRuntimeVersion>;
fn can_start_version_guard(&self) -> bool;
async fn raw_storage_value(
&self,
at: HashOf<C>,
storage_key: StorageKey,
) -> Result<Option<StorageData>>;
async fn storage_value<T: Decode + 'static>(
&self,
at: HashOf<C>,
storage_key: StorageKey,
) -> Result<Option<T>> {
self.raw_storage_value(at, storage_key.clone())
.await?
.map(|encoded_value| {
T::decode(&mut &encoded_value.0[..]).map_err(|e| {
Error::failed_to_read_storage_value::<C>(at, storage_key, e.into())
})
})
.transpose()
}
async fn storage_map_value<T: StorageMapKeyProvider>(
&self,
at: HashOf<C>,
pallet_prefix: &str,
storage_key: &T::Key,
) -> Result<Option<T::Value>> {
self.storage_value(at, T::final_key(pallet_prefix, storage_key)).await
}
async fn storage_double_map_value<T: StorageDoubleMapKeyProvider>(
&self,
at: HashOf<C>,
pallet_prefix: &str,
key1: &T::Key1,
key2: &T::Key2,
) -> Result<Option<T::Value>> {
self.storage_value(at, T::final_key(pallet_prefix, key1, key2)).await
}
async fn pending_extrinsics(&self) -> Result<Vec<Bytes>>;
async fn submit_unsigned_extrinsic(&self, transaction: Bytes) -> Result<HashOf<C>>;
async fn submit_signed_extrinsic(
&self,
signer: &AccountKeyPairOf<C>,
prepare_extrinsic: impl FnOnce(HeaderIdOf<C>, NonceOf<C>) -> Result<UnsignedTransaction<C>>
+ Send
+ 'static,
) -> Result<HashOf<C>>
where
C: ChainWithTransactions,
AccountIdOf<C>: From<<AccountKeyPairOf<C> as Pair>::Public>;
async fn submit_and_watch_signed_extrinsic(
&self,
signer: &AccountKeyPairOf<C>,
prepare_extrinsic: impl FnOnce(HeaderIdOf<C>, NonceOf<C>) -> Result<UnsignedTransaction<C>>
+ Send
+ 'static,
) -> Result<TransactionTracker<C, Self>>
where
C: ChainWithTransactions,
AccountIdOf<C>: From<<AccountKeyPairOf<C> as Pair>::Public>;
async fn validate_transaction<SignedTransaction: Encode + Send + 'static>(
&self,
at: HashOf<C>,
transaction: SignedTransaction,
) -> Result<TransactionValidity>;
async fn estimate_extrinsic_weight<SignedTransaction: Encode + Send + 'static>(
&self,
at: HashOf<C>,
transaction: SignedTransaction,
) -> Result<Weight>;
async fn raw_state_call<Args: Encode + Send>(
&self,
at: HashOf<C>,
method: String,
arguments: Args,
) -> Result<Bytes>;
async fn state_call<Args: Encode + Send, Ret: Decode>(
&self,
at: HashOf<C>,
method: String,
arguments: Args,
) -> Result<Ret> {
let encoded_arguments = arguments.encode();
let encoded_output = self.raw_state_call(at, method.clone(), arguments).await?;
Ret::decode(&mut &encoded_output.0[..]).map_err(|e| {
Error::failed_state_call::<C>(at, method, Bytes(encoded_arguments), e.into())
})
}
async fn prove_storage(
&self,
at: HashOf<C>,
keys: Vec<StorageKey>,
) -> Result<(StorageProof, HashOf<C>)>;
}