Skip to content

Commit

Permalink
Improve SDK docs (#254)
Browse files Browse the repository at this point in the history
* sdk: Cleanup `run` module docs

* sdk: Cleanup `random` module docs

* sdk: Cleanup `env` module docs, Add `Error::UnsupportedProtocol`

* sdk: Cleanup `tx` module docs

* sdk: Improve `slashing` module docs

* sdk: Cleanup docs in network setup module

* sdk: Cleanup keystore backend docs

* sdk: Improve keystore secrets docs

* sdk: Move events_watcher module docs to files

* sdk: Update for latest changes

* sdk: Make sure `LocalDatabase` doc tests don't run

* sdk: Document `slashing` module

* sdk: Document `mutex_ext` module

* sdk: Replace `lazy_static` with std `LazyLock`

* sdk: Document `metrics` module

* sdk: Document `Client` trait

* sdk: Document `benchmark` module

* sdk: Document `TangleRuntimeClient`

* sdk: Document `config` module

* sdk: Use `UserID` type in `channels` module

* sdk: Document `prometheus` and `metrics` module

* sdk: Expand feature gate on `prometheus` module

* sdk: Fix async doc test

* sdk: Fix async doc test
  • Loading branch information
Serial-ATA authored Sep 12, 2024
1 parent c8c569a commit 1b05803
Show file tree
Hide file tree
Showing 30 changed files with 409 additions and 128 deletions.
1 change: 0 additions & 1 deletion Cargo.lock

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

1 change: 0 additions & 1 deletion sdk/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ elliptic-curve = { workspace = true, features = ["alloc", "sec1"] }
getrandom = { workspace = true }
hex = { workspace = true, features = ["alloc"] }
http-body-util = { workspace = true }
lazy_static = { workspace = true }
lock_api = { workspace = true }
sqlx = { workspace = true, features = ["runtime-tokio-rustls", "sqlite"], optional = true }
parking_lot = { workspace = true, optional = true }
Expand Down
52 changes: 49 additions & 3 deletions sdk/src/benchmark/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pub use tokio;

/// The runtime trait that all runtimes must implement.
pub trait Runtime {
/// Runs the given future to completion on the runtime.
Expand All @@ -7,6 +8,9 @@ pub trait Runtime {
F: std::future::Future;
}

/// The [`tokio`](https://crates.io/crates/tokio) runtime.
///
/// This will execute the benchmark using the `tokio` runtime.
#[derive(Debug, Clone, Copy)]
pub struct TokioRuntime;

Expand All @@ -31,6 +35,9 @@ pub struct Bencher<R> {
cores: usize,
}

/// The results of a benchmark.
///
/// This implements [`Display`] to provide a human-readable summary of the benchmark.
#[derive(Debug, Clone)]
pub struct BenchmarkSummary {
/// The name of the benchmark.
Expand All @@ -46,6 +53,17 @@ pub struct BenchmarkSummary {
}

impl<R: Runtime> Bencher<R> {
/// Create a new benchmark harness.
///
/// # Examples
///
/// ```
/// use gadget_sdk::benchmark::{Bencher, TokioRuntime};
///
/// const THREADS: usize = 4;
///
/// let bencher = Bencher::new(THREADS, TokioRuntime);
/// ```
pub fn new(threads: usize, runtime: R) -> Self {
Self {
runtime,
Expand All @@ -54,16 +72,44 @@ impl<R: Runtime> Bencher<R> {
}
}

/// Runs the given future on the runtime.
/// Runs the given future on the [`Runtime`].
///
/// # Examples
///
/// ```no_run
/// use gadget_sdk::benchmark::{Bencher, TokioRuntime};
///
/// const THREADS: usize = 4;
///
/// let bencher = Bencher::new(THREADS, TokioRuntime);
/// bencher.block_on(async {
/// // Do some work...
/// });
/// ```
pub fn block_on<F>(&self, future: F) -> F::Output
where
F: std::future::Future,
{
self.runtime.block_on(future)
}

/// Stops the benchmark and returns a summary of the benchmark.
pub fn stop(&self, name: &str, job_id: u8) -> BenchmarkSummary {
/// Ends the benchmark and returns a summary.
///
/// # Examples
///
/// ```no_run
/// use gadget_sdk::benchmark::{Bencher, TokioRuntime};
/// const THREADS: usize = 4;
///
/// let bencher = Bencher::new(THREADS, TokioRuntime);
/// bencher.block_on(async {
/// // Do some work...
/// });
///
/// let summary = bencher.stop("my_benchmark", 0);
/// println!("{}", summary);
/// ```
pub fn stop<N: ToString>(&self, name: N, job_id: u8) -> BenchmarkSummary {
let pid = sysinfo::get_current_pid().expect("Failed to get current process ID");
let s = sysinfo::System::new_all();
let process = s
Expand Down
4 changes: 4 additions & 0 deletions sdk/src/clients/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ pub mod tangle;
#[async_trait]
#[auto_impl(Arc)]
pub trait Client<Event>: Clone + Send + Sync {
/// Fetch the next event from the client.
async fn next_event(&self) -> Option<Event>;
/// Fetch the latest event from the client.
///
/// If no event has yet been fetched, the client will call [`next_event`](Self::next_event).
async fn latest_event(&self) -> Option<Event>;
}
67 changes: 46 additions & 21 deletions sdk/src/clients/tangle/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ use subxt::events::Events;
use subxt::utils::AccountId32;
use subxt::{self, SubstrateConfig};

/// The [Config](subxt::Config) providing the runtime types.
pub type TangleConfig = SubstrateConfig;
/// The client used to perform API calls, using the [TangleConfig].
pub type TangleClient = subxt::OnlineClient<TangleConfig>;
pub type TangleBlock = Block<TangleConfig, TangleClient>;
pub type TangleBlockStream = subxt::backend::StreamOfResults<TangleBlock>;
type TangleBlock = Block<TangleConfig, TangleClient>;
type TangleBlockStream = subxt::backend::StreamOfResults<TangleBlock>;

#[derive(Clone, Debug)]
pub struct TangleEvent {
Expand All @@ -26,41 +28,40 @@ pub struct TangleEvent {

#[derive(Clone, Debug)]
pub struct TangleRuntimeClient {
client: subxt::OnlineClient<SubstrateConfig>,
finality_notification_stream: Arc<gadget_io::tokio::sync::Mutex<Option<TangleBlockStream>>>,
latest_finality_notification: Arc<gadget_io::tokio::sync::Mutex<Option<TangleEvent>>>,
client: TangleClient,
finality_notification_stream: Arc<tokio::sync::Mutex<Option<TangleBlockStream>>>,
latest_finality_notification: Arc<tokio::sync::Mutex<Option<TangleEvent>>>,
account_id: AccountId32,
}

impl TangleRuntimeClient {
/// Create a new Tangle runtime client from a RPC url.
pub async fn from_url(url: &str, account_id: AccountId32) -> Result<Self, Error> {
let client = subxt::OnlineClient::<SubstrateConfig>::from_url(url).await?;
/// Create a new Tangle runtime client from an RPC url.
///
/// # Errors
///
/// * `url` is not a valid URL.
/// * `url` is not a secure (https:// or wss://) URL.
/// * `url` cannot be resolved.
pub async fn from_url<U: AsRef<str>>(url: U, account_id: AccountId32) -> Result<Self, Error> {
let client = TangleClient::from_url(url).await?;
Ok(Self::new(client, account_id))
}

/// Create a new TangleRuntime instance.
pub fn new(client: subxt::OnlineClient<SubstrateConfig>, account_id: AccountId32) -> Self {
/// Create a new Tangle runtime client from an existing [`TangleClient`].
pub fn new(client: TangleClient, account_id: AccountId32) -> Self {
Self {
client,
finality_notification_stream: Arc::new(gadget_io::tokio::sync::Mutex::new(None)),
latest_finality_notification: Arc::new(gadget_io::tokio::sync::Mutex::new(None)),
finality_notification_stream: Arc::new(tokio::sync::Mutex::new(None)),
latest_finality_notification: Arc::new(tokio::sync::Mutex::new(None)),
account_id,
}
}

pub fn client(&self) -> subxt::OnlineClient<SubstrateConfig> {
/// Get the associated [`TangleClient`]
pub fn client(&self) -> TangleClient {
self.client.clone()
}

/// Initialize the TangleRuntime instance by listening for finality notifications.
/// This method must be called before using the instance.
async fn initialize(&self) -> Result<(), Error> {
let finality_notification_stream = self.client.blocks().subscribe_finalized().await?;
*self.finality_notification_stream.lock().await = Some(finality_notification_stream);
Ok(())
}

pub fn runtime_api(
&self,
at: [u8; 32],
Expand All @@ -69,9 +70,33 @@ impl TangleRuntimeClient {
self.client.runtime_api().at(block_ref)
}

/// Get the associated account ID
///
/// # Examples
///
/// ```no_run
/// use gadget_sdk::clients::tangle::runtime::TangleRuntimeClient;
/// use subxt::utils::AccountId32;
///
/// # async fn foo() -> Result<(), gadget_sdk::Error>{
/// let account_id = AccountId32::from([0; 32]);
/// let client = TangleRuntimeClient::from_url("https://foo.bar", account_id.clone()).await?;
///
/// assert_eq!(client.account_id(), &account_id);
/// # Ok(()) }
/// ```
pub fn account_id(&self) -> &AccountId32 {
&self.account_id
}

// Initialize the `TangleRuntimeClient` to listen for finality notifications.
//
// NOTE: This method must be called before using the instance.
async fn initialize(&self) -> Result<(), Error> {
let finality_notification_stream = self.client.blocks().subscribe_finalized().await?;
*self.finality_notification_stream.lock().await = Some(finality_notification_stream);
Ok(())
}
}

#[async_trait::async_trait]
Expand Down
13 changes: 13 additions & 0 deletions sdk/src/clients/tangle/services.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,29 @@ pub struct ServicesClient<C: Config> {
}

impl<C: Config> ServicesClient<C> {
/// Create a new services client
pub fn new(logger: Logger, rpc_client: OnlineClient<C>) -> Self {
Self { logger, rpc_client }
}

/// Get the associated RPC client
pub fn rpc_client(&self) -> &OnlineClient<C> {
&self.rpc_client
}
}

/// A list of services provided by an operator, along with their blueprint
pub type RpcServicesWithBlueprint = services::RpcServicesWithBlueprint<AccountId32, u64>;

impl<C: Config> ServicesClient<C>
where
BlockRef<<C as Config>::Hash>: From<BlockRef<H256>>,
{
/// Get the blueprint with the given ID at the given block
///
/// # Errors
///
/// Returns an error if the blueprint could not be fetched
pub async fn get_blueprint_by_id(
&self,
at: [u8; 32],
Expand All @@ -51,6 +59,11 @@ where
Ok(ret)
}

/// Get the services provided by the operator at `address`
///
/// # Errors
///
/// Returns an error if the services could not be fetched
pub async fn query_operator_blueprints(
&self,
at: [u8; 32],
Expand Down
38 changes: 25 additions & 13 deletions sdk/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use crate::events_watcher::tangle::TangleConfig;
use crate::keystore::backend::GenericKeyStore;
use alloc::string::{String, ToString};

/// The protocol on which a gadget will be executed.
#[derive(Default, Debug, Clone, Copy)]
pub enum Protocol {
#[default]
Expand All @@ -12,17 +13,25 @@ pub enum Protocol {

impl Protocol {
/// Returns the protocol from the environment variable `PROTOCOL`.
///
/// If the environment variable is not set, it defaults to `Protocol::Tangle`.
///
/// # Errors
///
/// * [`Error::UnsupportedProtocol`] if the protocol is unknown. See [`Protocol`].
#[cfg(feature = "std")]
pub fn from_env() -> Self {
std::env::var("PROTOCOL")
.map(|v| v.parse::<Protocol>().unwrap_or_default())
.unwrap_or_default()
pub fn from_env() -> Result<Self, Error> {
if let Ok(protocol) = std::env::var("PROTOCOL") {
return protocol.to_ascii_lowercase().parse::<Protocol>();
}

Ok(Protocol::default())
}

/// Returns the protocol from the environment variable `PROTOCOL`.
#[cfg(not(feature = "std"))]
pub fn from_env() -> Self {
Self::Tangle
pub fn from_env() -> Result<Self, Error> {
Ok(Protocol::default())
}
}

Expand All @@ -36,13 +45,13 @@ impl core::fmt::Display for Protocol {
}

impl core::str::FromStr for Protocol {
type Err = ();
type Err = Error;

fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"tangle" => Ok(Self::Tangle),
"eigenlayer" => Ok(Self::Eigenlayer),
_ => Err(()),
_ => Err(Error::UnsupportedProtocol(s.to_string())),
}
}
}
Expand Down Expand Up @@ -99,7 +108,7 @@ pub struct GadgetConfiguration<RwLock: lock_api::RawRwLock> {
_lock: core::marker::PhantomData<RwLock>,
}

/// An error type for the gadget environment.
/// Errors that can occur while loading and using the gadget configuration.
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum Error {
Expand Down Expand Up @@ -131,6 +140,9 @@ pub enum Error {
#[error(transparent)]
#[cfg(any(feature = "std", feature = "wasm"))]
Subxt(#[from] subxt::Error),
/// Error parsing the protocol, from the `PROTOCOL` environment variable.
#[error("Unsupported protocol: {0}")]
UnsupportedProtocol(String),

/// No Sr25519 keypair found in the keystore.
#[error("No Sr25519 keypair found in the keystore")]
Expand Down Expand Up @@ -241,8 +253,8 @@ impl<RwLock: lock_api::RawRwLock> GadgetConfiguration<RwLock> {
///
/// # Errors
///
/// This function will return an error if no Sr25519 keypair is found in the keystore.
/// or if the keypair seed is invalid.
/// * No sr25519 keypair is found in the keystore.
/// * The keypair seed is invalid.
#[doc(alias = "sr25519_signer")]
pub fn first_signer(&self) -> Result<subxt_signer::sr25519::Keypair, Error> {
let keystore = self.keystore()?;
Expand All @@ -263,8 +275,8 @@ impl<RwLock: lock_api::RawRwLock> GadgetConfiguration<RwLock> {
///
/// # Errors
///
/// This function will return an error if no ECDSA keypair is found in the keystore.
/// or if the keypair seed is invalid.
/// * No ECDSA keypair is found in the keystore.
/// * The keypair seed is invalid.
#[doc(alias = "ecdsa_signer")]
pub fn first_ecdsa_signer(&self) -> Result<tangle_subxt::subxt_signer::ecdsa::Keypair, Error> {
let keystore = self.keystore()?;
Expand Down
4 changes: 3 additions & 1 deletion sdk/src/events_watcher/evm.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//! EVM Event Watcher Module
use crate::events_watcher::{error::Error, ConstantWithMaxRetryCount};
use crate::store::LocalDatabase;
use alloy_network::Network;
Expand Down Expand Up @@ -125,7 +127,7 @@ pub trait EventWatcher<T: Config>: Send + Sync {
contract: Self::Contract,
handlers: Vec<EventHandlerFor<Self, T>>,
) -> Result<(), Error> {
let local_db = LocalDatabase::new("./db");
let local_db = LocalDatabase::open("./db");
let backoff = backoff::backoff::Constant::new(Duration::from_secs(1));
let task = || async {
let step = 100;
Expand Down
Loading

0 comments on commit 1b05803

Please sign in to comment.