Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add faucet pallet to CLI #590

Merged
merged 8 commits into from
Nov 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
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
Binary file modified cli/artifacts/metadata.scale
Binary file not shown.
60 changes: 60 additions & 0 deletions cli/polka-storage/storagext-cli/src/cmd/faucet.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
use std::time::Duration;

use anyhow::anyhow;
use clap::Subcommand;
use storagext::{FaucetClientExt, PolkaStorageConfig};
use url::Url;

use crate::OutputFormat;

#[derive(Debug, Subcommand)]
#[command(name = "faucet", about = "CLI Client to the Faucet Pallet", version)]
pub(crate) enum FaucetCommand {
/// Drip funds into target account.
Drip {
/// Drip target's account ID.
account_id: <PolkaStorageConfig as subxt::Config>::AccountId,
},
}

impl FaucetCommand {
/// Run a `faucet` command.
///
/// Requires the target RPC address.
#[tracing::instrument(level = "info", skip(self, node_rpc), fields(node_rpc = node_rpc.as_str()))]
pub async fn run(
self,
node_rpc: Url,
n_retries: u32,
retry_interval: Duration,
output_format: OutputFormat,
wait_for_finalization: bool,
) -> Result<(), anyhow::Error> {
let client = storagext::Client::new(node_rpc, n_retries, retry_interval).await?;

match self {
FaucetCommand::Drip { account_id } => {
let submission_result = client.drip(account_id, wait_for_finalization).await?;

let Some(submission_result) = submission_result else {
// Didn't wait for finalization
return Ok(());
};

// Grab `Dripped` event and convert into `::faucet::Event` so we have `Display` and `Serialize` implemented.
let event: storagext::runtime::faucet::Event = submission_result
.events
.find_first::<storagext::runtime::faucet::events::Dripped>()?
.ok_or(anyhow!("Could not find expected Dripped event"))?
.into();

let output = output_format.format(&event)?;
match output_format {
OutputFormat::Plain => println!("[{}] {}", submission_result.hash, output),
OutputFormat::Json => println!("{}", output),
}
Ok(())
}
}
}
}
1 change: 1 addition & 0 deletions cli/polka-storage/storagext-cli/src/cmd/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod faucet;
pub mod market;
pub mod proofs;
pub mod randomness;
Expand Down
16 changes: 14 additions & 2 deletions cli/polka-storage/storagext-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ use std::{fmt::Debug, time::Duration};

use clap::{ArgGroup, Parser, Subcommand};
use cmd::{
market::MarketCommand, proofs::ProofsCommand, randomness::RandomnessCommand,
storage_provider::StorageProviderCommand, system::SystemCommand,
faucet::FaucetCommand, market::MarketCommand, proofs::ProofsCommand,
randomness::RandomnessCommand, storage_provider::StorageProviderCommand, system::SystemCommand,
};
use storagext::multipair::{DebugPair, MultiPairSigner};
use subxt::ext::sp_core::{
Expand Down Expand Up @@ -89,6 +89,8 @@ struct Cli {

#[derive(Debug, Subcommand)]
enum SubCommand {
#[command(subcommand)]
Faucet(FaucetCommand),
// Perform market operations.
#[command(subcommand)]
Market(MarketCommand),
Expand All @@ -114,6 +116,16 @@ impl SubCommand {
wait_for_finalization: bool,
) -> Result<(), anyhow::Error> {
match self {
SubCommand::Faucet(cmd) => {
cmd.run(
node_rpc,
n_retries,
retry_interval,
output_format,
wait_for_finalization,
)
.await?;
}
SubCommand::Market(cmd) => {
cmd.run(
node_rpc,
Expand Down
30 changes: 30 additions & 0 deletions cli/polka-storage/storagext/src/clients/faucet.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
use std::future::Future;

use crate::{
runtime::{self, SubmissionResult},
PolkaStorageConfig,
};

/// Client to interact with the faucet pallet.
pub trait FaucetClientExt {
/// Drip funds into the provided account.
fn drip(
&self,
account_id: <PolkaStorageConfig as subxt::Config>::AccountId,
wait_for_finalization: bool,
) -> impl Future<Output = Result<Option<SubmissionResult<PolkaStorageConfig>>, subxt::Error>>;
}

impl FaucetClientExt for crate::runtime::client::Client {
async fn drip(
&self,
account_id: <PolkaStorageConfig as subxt::Config>::AccountId,
wait_for_finalization: bool,
) -> Result<Option<SubmissionResult<PolkaStorageConfig>>, subxt::Error> {
let payload = runtime::tx()
.faucet()
.drip(subxt::utils::AccountId32::from(account_id));

self.unsigned(&payload, wait_for_finalization).await
}
}
2 changes: 2 additions & 0 deletions cli/polka-storage/storagext/src/clients/mod.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
mod faucet;
mod market;
mod proofs;
mod randomness;
mod storage_provider;
mod system;

pub use faucet::FaucetClientExt;
pub use market::MarketClientExt;
pub use proofs::ProofsClientExt;
pub use randomness::RandomnessClientExt;
Expand Down
5 changes: 4 additions & 1 deletion cli/polka-storage/storagext/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ pub mod types;
pub mod deser;

pub use crate::{
clients::{MarketClientExt, RandomnessClientExt, StorageProviderClientExt, SystemClientExt},
clients::{
FaucetClientExt, MarketClientExt, RandomnessClientExt, StorageProviderClientExt,
SystemClientExt,
},
runtime::{bounded_vec::IntoBoundedByteVec, client::Client},
};

Expand Down
52 changes: 36 additions & 16 deletions cli/polka-storage/storagext/src/runtime/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::time::Duration;

use codec::Encode;
use hex::ToHex;
use subxt::{blocks::Block, events::Events, OnlineClient};
use subxt::{blocks::Block, events::Events, utils::H256, OnlineClient};

use crate::PolkaStorageConfig;

Expand Down Expand Up @@ -67,6 +67,32 @@ impl Client {
}
}

pub(crate) async fn unsigned<Call>(
&self,
call: &Call,
wait_for_finalization: bool,
) -> Result<Option<SubmissionResult<PolkaStorageConfig>>, subxt::Error>
where
Call: subxt::tx::Payload,
{
if wait_for_finalization {
let submitted_extrinsic_hash = self.client.tx().create_unsigned(call)?.submit().await?;
self.traced_submission_with_finalization(submitted_extrinsic_hash)
.await
.map(Option::Some)
} else {
tracing::trace!("submitting unsigned extrinsic");
let extrinsic_hash = self.client.tx().create_unsigned(call)?.submit().await?;

tracing::trace!(
extrinsic_hash = extrinsic_hash.encode_hex::<String>(),
"waiting for finalization"
);

Ok(None)
}
}

/// Submit an extrinsic and wait for finalization, returning the block hash it was included in.
///
/// Equivalent to performing [`OnlineClient::sign_and_submit_then_watch_default`],
Expand All @@ -82,7 +108,12 @@ impl Client {
Keypair: subxt::tx::Signer<PolkaStorageConfig>,
{
if wait_for_finalization {
self.traced_submission_with_finalization(call, account_keypair)
let submitted_extrinsic_hash = self
.client
.tx()
.sign_and_submit_default(call, account_keypair)
.await?;
self.traced_submission_with_finalization(submitted_extrinsic_hash)
.await
.map(Option::Some)
} else {
Expand All @@ -101,25 +132,14 @@ impl Client {
}
}

pub(crate) async fn traced_submission_with_finalization<Call, Keypair>(
pub(crate) async fn traced_submission_with_finalization(
&self,
call: &Call,
account_keypair: &Keypair,
) -> Result<SubmissionResult<PolkaStorageConfig>, subxt::Error>
where
Call: subxt::tx::Payload,
Keypair: subxt::tx::Signer<PolkaStorageConfig>,
{
submitted_extrinsic_hash: H256,
) -> Result<SubmissionResult<PolkaStorageConfig>, subxt::Error> {
tracing::trace!("submitting extrinsic");

let mut finalized_block_stream = self.client.blocks().subscribe_finalized().await?;

let submitted_extrinsic_hash = self
.client
.tx()
.sign_and_submit_default(call, account_keypair)
.await?;

tracing::debug!(
extrinsic_hash = submitted_extrinsic_hash.encode_hex::<String>(),
"waiting for finalization"
Expand Down
20 changes: 20 additions & 0 deletions cli/polka-storage/storagext/src/runtime/display/faucet.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use crate::runtime::faucet::Event;

impl std::fmt::Display for Event {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Event::Dripped { who, when } => f.write_fmt(format_args!(
"Faucet Dripped: {{ account: {who}, block: {when} }}"
)),
}
}
}

impl From<crate::runtime::faucet::events::Dripped> for Event {
fn from(value: crate::runtime::faucet::events::Dripped) -> Self {
Self::Dripped {
who: value.who,
when: value.when,
}
}
}
1 change: 1 addition & 0 deletions cli/polka-storage/storagext/src/runtime/display/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
mod faucet;
mod market;
mod proofs;
mod storage_provider;
Expand Down
4 changes: 4 additions & 0 deletions cli/polka-storage/storagext/src/runtime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ pub mod display;
path = "pallet_proofs::pallet::Event",
derive = "::serde::Serialize"
),
derive_for_type(
path = "pallet_faucet::pallet::Event",
derive = "::serde::Serialize"
),
derive_for_type(
path = "bounded_collections::bounded_vec::BoundedVec",
derive = "::serde::Serialize"
Expand Down
2 changes: 2 additions & 0 deletions docs/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
- [Storage Provider](./architecture/pallets/storage-provider.md)
- [Proofs](./architecture/pallets/proofs.md)
- [Randomness](./architecture/pallets/randomness.md)
- [Faucet](./architecture/pallets/faucet.md)
- [Getting Started](./getting-started/index.md)
- [Building](./getting-started/building/index.md)
- [From Source](./getting-started/building/source.md)
Expand All @@ -35,6 +36,7 @@
- [`proofs`](./storagext-cli/proofs.md)
- [`randomness`](./storagext-cli/randomness.md)
- [`system`](./storagext-cli/system.md)
- [`faucet`](./storagext-cli/faucet.md)
- [Mater CLI](./mater-cli/index.md)
- [Zombienet Configuration](./zombienet-config.md)

Expand Down
68 changes: 68 additions & 0 deletions docs/src/architecture/pallets/faucet.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# Faucet Pallet

## Table of Contents

- [Faucet Pallet](#faucet-pallet)
- [Table of Contents](#table-of-contents)
- [Overview](#overview)
- [Usage](#usage)
- [Extrinsics](#extrinsics)
- [`drip`](#drip)
- [Events](#events)
- [Errors](#errors)
- [Constants](#constants)

## Overview

The Faucet Pallet enables users to drip funds into their wallet to start using the polka-storage chain.

<div class="warning">

The faucet pallet only exists on the testnet. Any of the funds dripped do not have any real-world value.

</div>

## Usage

The Faucet Pallet is used to get funds on testnet into an externally generated account.

> Only 1 drip per 24 hours per account is allowed. When trying to drip more often than once per 24 hours the transaction will be rejected.

## Extrinsics

### `drip`

The `drip` extrinsic is an [unsigned extrinsic (or inherit)](https://docs.substrate.io/learn/transaction-types/#unsigned-transactions) with no gas fees. This means that any account can get funds, even if their current balance is 0.

| Name | Description | Type |
| --------- | --------------------------------------- | ------------------------------------------------------------------------ |
| `account` | The target account to transfer funds to | [SS58 address](https://docs.substrate.io/learn/accounts-addresses-keys/) |

#### <a class="header" id="register_storage_provider.example" href="#register_storage_provider.example">Example</a>

```bash
storagext-cli faucet drip 5GpRRVXgPSoKVmUzyinpJPiCjfn98DsuuHgMV2f9s5NCzG19
```

## Events

The Faucet Pallet only emits a single event:

- `Dripped` - Emits what account was dripped to and at what block number.
- `who` - [SS58 address](https://docs.substrate.io/learn/accounts-addresses-keys/) of the dripped account.
- `when` - Block at which the drip occurred.

## Errors

The Faucet Pallet actions can fail with the following errors:

- `FaucetUsedRecently` - the provided account had funds dripped within the last 24 hours.

## Constants

The Faucet Pallet has the following constants:

| Name | Description | Value |
| ------------------ | --------------------------------------------------------------------- | ------------------ |
| `FaucetDripAmount` | The amount that is dispensed in [planck](../../glossary.md#planck)'s. | 10_000_000_000_000 |
| `FaucetDripDelay` | How often an account can be topped up. | 1 Day |
2 changes: 1 addition & 1 deletion docs/src/architecture/pallets/randomness.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ The Randomness Pallet actions can fail with the following errors:

## Constants

The Storage Provider Pallet has the following constants:
The Randomness Pallet has the following constants:

| Name | Description | Value |
| ----------------- | ----------------------------------------------------------------- | ------- |
Expand Down
Loading