Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
A0-1608 Add documentation of all public API and traits
  • Loading branch information
Marcin-Radecki committed Dec 28, 2022
commit e2d6c41379ce7d11f4783bf8d03b090d26b1976f
2 changes: 1 addition & 1 deletion aleph-client/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion aleph-client/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "aleph_client"
version = "2.4.0"
version = "2.5.0"
edition = "2021"
license = "Apache 2.0"

Expand Down
8 changes: 7 additions & 1 deletion aleph-client/src/aleph_zero.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
#[allow(dead_code, unused_imports, non_camel_case_types)]
#[doc(hidden)]
#[allow(
dead_code,
unused_imports,
non_camel_case_types,
rustdoc::broken_intra_doc_links
)]
pub mod api {
use super::api as root_mod;
pub static PALLETS: [&str; 21usize] = [
Expand Down
87 changes: 86 additions & 1 deletion aleph-client/src/connections.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,36 @@ use subxt::{

use crate::{api, sp_weights::weight_v2::Weight, BlockHash, Call, Client, KeyPair, TxStatus};

/// Capable of communicating with a live Aleph chain.
#[derive(Clone)]
pub struct Connection {
/// A `subxt` object representing a communication channel to a live chain.
/// Requires an url address for creation.
pub client: Client,
}

/// Any connection that is signed by some key.
pub struct SignedConnection {
/// Composition of [`Connection`] object.
pub connection: Connection,
/// A key which signs any txes send via this connection.
pub signer: KeyPair,
}

/// Specific connection that is singed by the sudo key.
pub struct RootConnection {
/// Composition of [`Connection`] object.
pub connection: Connection,
/// Sudo key pair.
pub root: KeyPair,
}

/// API for [sudo pallet](https://paritytech.github.io/substrate/master/pallet_sudo/index.html).
#[async_trait::async_trait]
pub trait SudoCall {
/// API for [`sudo_unchecked_weight`](https://paritytech.github.io/substrate/master/pallet_sudo/pallet/enum.Call.html#variant.sudo_unchecked_weight) call.
async fn sudo_unchecked(&self, call: Call, status: TxStatus) -> anyhow::Result<BlockHash>;
/// API for [`sudo`](https://paritytech.github.io/substrate/master/pallet_sudo/pallet/enum.Call.html#variant.sudo) call.
async fn sudo(&self, call: Call, status: TxStatus) -> anyhow::Result<BlockHash>;
}

Expand Down Expand Up @@ -62,10 +74,16 @@ impl Connection {
const DEFAULT_RETRIES: u32 = 10;
const RETRY_WAIT_SECS: u64 = 1;

/// Creates new connection from a given url.
/// By default, it tries to connect 10 times, waiting 1 second between each unsuccessful attempt.
/// * `address` - address in websocket format, e.g. `ws://127.0.0.1:9943`
pub async fn new(address: String) -> Self {
Self::new_with_retries(address, Self::DEFAULT_RETRIES).await
}

/// Creates new connection from a given url and given number of connection attempts.
/// * `address` - address in websocket format, e.g. `ws://127.0.0.1:9943`
/// * `retries` - number of connection attempts
pub async fn new_with_retries(address: String, mut retries: u32) -> Self {
loop {
let client = Client::from_url(&address).await;
Expand All @@ -80,6 +98,13 @@ impl Connection {
}
}

/// Retrieves a decoded storage value stored under given storage key.
///
/// # Panic
/// This method `panic`s, in case storage key is invalid, or in case value cannot be decoded,
/// or there is no such value
/// * `addrs` - represents a storage key, see [more info about keys](https://docs.substrate.io/fundamentals/state-transitions-and-storage/#querying-storage)
/// * `at` - optional block hash to query state from
pub async fn get_storage_entry<T: DecodeWithMetadata, Defaultable, Iterable>(
&self,
addrs: &StaticStorageAddress<T, Yes, Defaultable, Iterable>,
Expand All @@ -90,6 +115,19 @@ impl Connection {
.expect("There should be a value")
}

/// Retrieves a decoded storage value stored under given storage key.
///
/// # Panic
/// This method `panic`s, in case storage key is invalid, or in case value cannot be decoded,
/// but does _not_ `panic` if there is no such value
/// * `addrs` - represents a storage key, see [more info about keys](https://docs.substrate.io/fundamentals/state-transitions-and-storage/#querying-storage)
/// * `at` - optional block hash to query state from
///
/// # Examples
/// ```rust
/// let addrs = api::storage().treasury().proposal_count();
/// get_storage_entry_maybe(&addrs, None).await
/// ```
pub async fn get_storage_entry_maybe<T: DecodeWithMetadata, Defaultable, Iterable>(
&self,
addrs: &StaticStorageAddress<T, Yes, Defaultable, Iterable>,
Expand All @@ -103,6 +141,21 @@ impl Connection {
.expect("Should access storage")
}

/// Submit a RPC call.
///
/// * `func_name` - name of a RPC call
/// * `params` - result of calling `rpc_params!` macro, that's `Vec<u8>` of encoded data
/// to this rpc call
///
/// # Examples
/// ```rust
/// let func_name = "alephNode_emergencyFinalize";
/// let hash = BlockHash::from_str("0x37841c5a09db7d9f985f2306866f196365f1bb9372efc76086e07b882296e1cc").expect("Hash is properly hex encoded");
/// let signature = key_pair.sign(&hash.encode());
/// let raw_signature: &[u8] = signature.as_ref();
/// let params = rpc_params![raw_signature, hash, number];
/// let _: () = rpc_call(func_name.to_string(), params).await?;
/// ```
pub async fn rpc_call<R: Decode>(
&self,
func_name: String,
Expand All @@ -116,14 +169,31 @@ impl Connection {
}

impl SignedConnection {
/// Creates new signed connection from a given url.
/// * `address` - address in websocket format, e.g. `ws://127.0.0.1:9943`
/// * `signer` - a [`KeyPair`] of signing account
pub async fn new(address: String, signer: KeyPair) -> Self {
Self::from_connection(Connection::new(address).await, signer)
}

/// Creates new signed connection from existing [`Connection]` object.
/// * `connection` - existing connection
/// * `signer` - a [`KeyPair`] of signing account
pub fn from_connection(connection: Connection, signer: KeyPair) -> Self {
Self { connection, signer }
}

/// Send a transaction to a chain. It waits for a given tx `status`.
/// * `tx` - encoded transaction payload
/// * `status` - tx status
/// # Returns
/// Block hash of block where transaction was put or error
/// # Examples
/// ```rust
/// let tx = api::tx()
/// .balances()
/// .transfer(MultiAddress::Id(dest), amount);
/// send_tx(tx, status).await
/// ```
pub async fn send_tx<Call: TxPayload>(
&self,
tx: Call,
Expand All @@ -133,6 +203,12 @@ impl SignedConnection {
.await
}

/// Send a transaction to a chain. It waits for a given tx `status`.
/// * `tx` - encoded transaction payload
/// * `params` - optional tx params e.g. tip
/// * `status` - tx status
/// # Returns
/// Block hash of block where transaction was put or error
pub async fn send_tx_with_params<Call: TxPayload>(
&self,
tx: Call,
Expand Down Expand Up @@ -162,10 +238,18 @@ impl SignedConnection {
}

impl RootConnection {
/// Creates new root connection from a given url.
/// By default, it tries to connect 10 times, waiting 1 second between each unsuccessful attempt.
/// * `address` - address in websocket format, e.g. `ws://127.0.0.1:9943`
/// * `root` - a [`KeyPair`] of the Sudo account
pub async fn new(address: String, root: KeyPair) -> anyhow::Result<Self> {
RootConnection::try_from_connection(Connection::new(address).await, root).await
}

/// Creates new root connection from a given [`Connection`] object. It validates whether given
/// key is really a sudo account
/// * `connection` - existing connection
/// * `signer` - a [`KeyPair`] of the Sudo account
pub async fn try_from_connection(
connection: Connection,
signer: KeyPair,
Expand All @@ -191,6 +275,7 @@ impl RootConnection {
})
}

/// Converts [`RootConnection`] to [`SignedConnection`]
pub fn as_signed(&self) -> SignedConnection {
SignedConnection {
connection: self.connection.clone(),
Expand Down
30 changes: 30 additions & 0 deletions aleph-client/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
#![warn(missing_docs)]
//! API for [aleph-node](https://github.com/Cardinal-Cryptography/aleph-node) chain.
//!
//! This crate provides a Rust application interface for submitting transactions to `aleph-node` chain.
//! Most of the [pallets](https://docs.substrate.io/reference/frame-pallets/) are common to any
//! [Substrate](https://github.com/paritytech/substrate) chain, but there are some unique to `aleph-node`,
//! e.g. [`pallets::elections::ElectionsApi`].
//!
extern crate core;

pub use subxt::ext::sp_core::Pair;
Expand All @@ -13,44 +21,66 @@ use crate::api::runtime_types::aleph_runtime::RuntimeCall as Call;
mod aleph_zero;
mod connections;
pub mod contract;
/// API for pallets.
pub mod pallets;
mod runtime_types;
/// Block / session / era api.
pub mod utility;
/// Waiting for some events api.
pub mod waiting;

pub use aleph_zero::api;
pub use runtime_types::*;

/// An alias for a configuration of live chain, e.g. block index type, hash type.
pub type AlephConfig = PolkadotConfig;
/// An alias for a pallet aleph keys.
pub type AlephKeyPair = ed25519::Pair;
/// An alias for a type of a key pair that signs chain transactions.
pub type RawKeyPair = sr25519::Pair;
/// An alias for a signer object that constructs [`sr25519::Pair`] from given account id type.
pub type KeyPair = PairSigner<AlephConfig, sr25519::Pair>;
/// An alias for an account id type.
pub type AccountId = subxt::ext::sp_core::crypto::AccountId32;
/// An alias for a client type.
pub type Client = OnlineClient<AlephConfig>;
/// An alias for a hash type.
pub type BlockHash = H256;

pub use connections::{Connection, RootConnection, SignedConnection, SudoCall};

/// When submitting a transaction, wait for given status before proceeding.
#[derive(Copy, Clone)]
pub enum TxStatus {
/// A tx must be included in some block.
InBlock,
/// A tx must be included in some finalized block.
Finalized,
/// A tx must be successfully submitted.
Submitted,
}

/// Converts given seed phrase to a sr25519 [`KeyPair`] object.
/// * `seed` - a 12 or 24 word seed phrase
pub fn keypair_from_string(seed: &str) -> KeyPair {
let pair = sr25519::Pair::from_string(seed, None).expect("Can't create pair from seed value");
KeyPair::new(pair)
}

/// Converts given seed phrase to a sr25519 [`RawKeyPair`] object.
/// * `seed` - a 12 or 24 word seed phrase
pub fn raw_keypair_from_string(seed: &str) -> RawKeyPair {
sr25519::Pair::from_string(seed, None).expect("Can't create pair from seed value")
}

/// Converts given seed phrase to a ed25519 [`AlephKeyPair`] object.
/// * `seed` - a 12 or 24 word seed phrase
pub fn aleph_keypair_from_string(seed: &str) -> AlephKeyPair {
ed25519::Pair::from_string(seed, None).expect("Can't create pair from seed value")
}

/// Converts a key pair object to `AccountId`.
/// * `keypair` - a key-pair object, e.g. [`ed25519::Pair`] or [`sr25519::Pair`]
pub fn account_from_keypair<P>(keypair: &P) -> AccountId
where
P: Pair,
Expand Down
17 changes: 17 additions & 0 deletions aleph-client/src/pallets/aleph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,27 @@ use crate::{
Connection, Pair, RootConnection, SudoCall, TxStatus,
};

// TODO replace docs with link to pallet aleph docs, once they are published
/// Any object that implements pallet aleph API that requires sudo.
#[async_trait::async_trait]
pub trait AlephSudoApi {
/// Sets the emergency finalization key.
/// * `finalizer` - a new finalizer key
/// * `status` - a [`TxStatus`] of a tx to wait for
/// # Returns
/// Block hash of block where transaction was put or error
async fn set_emergency_finalizer(
&self,
finalizer: AccountId,
status: TxStatus,
) -> anyhow::Result<BlockHash>;

/// Schedules a finality version change for a future session.
/// * `version` - next version of the finalizer
/// * `session` - from which session the next version applies
/// * `status` - a [`TxStatus`] of a tx to wait for
/// # Returns
/// Block hash of block where transaction was put or error
async fn schedule_finality_version_change(
&self,
version: u32,
Expand All @@ -29,8 +42,12 @@ pub trait AlephSudoApi {
) -> anyhow::Result<BlockHash>;
}

/// Any object that implements pallet aleph RPC api.
#[async_trait::async_trait]
pub trait AlephRpc {
/// Finalize the block with given hash and number using attached signature.
/// # Returns
/// Block hash of block where transaction was put or error
async fn emergency_finalize(
&self,
number: BlockNumber,
Expand Down
2 changes: 2 additions & 0 deletions aleph-client/src/pallets/author.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ use codec::Decode;

use crate::{aleph_runtime::SessionKeys, Connection};

/// Any object that implements `author` RPC.
#[async_trait::async_trait]
pub trait AuthorRpc {
/// API for [`rotate_keys`](https://paritytech.github.io/substrate/master/sc_rpc/author/struct.Author.html#method.rotate_keys) call
async fn author_rotate_keys(&self) -> SessionKeys;
}

Expand Down
Loading