Skip to content

Commit d881aab

Browse files
authored
docs: document faucet usage and proof-of-work (#112)
Closes CHAIN-90
1 parent beb3529 commit d881aab

File tree

3 files changed

+42
-64
lines changed

3 files changed

+42
-64
lines changed

pallets/faucet/src/ext.rs

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,7 @@
1-
//! Type aliases for the faucet pallet
2-
//!
3-
//! This module contains type definitions used throughout the faucet pallet code.
4-
51
use polkadot_sdk::frame_support::traits::Currency;
62

7-
/// Type alias for the Balance type used in the pallet
8-
///
9-
/// This represents the token amount type in the system, derived from the Currency configuration.
103
pub(super) type BalanceOf<T> = <<T as crate::Config>::Currency as Currency<
114
<T as polkadot_sdk::frame_system::Config>::AccountId,
125
>>::Balance;
136

14-
/// Type alias for the AccountId type used in the pallet
15-
///
16-
/// This represents the account identifier type in the system.
177
pub(super) type AccountIdOf<T> = <T as polkadot_sdk::frame_system::Config>::AccountId;

pallets/faucet/src/faucet.rs

Lines changed: 33 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,36 @@
1-
//! Implementation of the faucet functionality
1+
//! # proof-of-work
22
//!
3-
//! This module contains the core logic for the faucet pallet, including:
4-
//! - The execution function that handles faucet requests
5-
//! - Hash calculation and verification functions for proof-of-work
6-
//! - Block hash retrieval and validation functions
3+
//! The following steps are required to generate a valid proof-of-work:
4+
//! - Concatenate the current block hash with the receiver key bytes and hash the result using keccak256. (reference [hash_block_and_key])
5+
//! - Concatenate a random nonce with the result of the previous step, hash it with sha256 and again with keccak256. (reference [create_seal_hash])
6+
//! - Transform the result hash to a u128 number and multiply it by 1_000_000. (reference [hash_meets_difficulty])
7+
//! - If the multiplication result exceeds the maximum possible u128 value, the hash is invalid. Try again with a new random nonce and updated block hash.
8+
//! - If it doesn't, the proof-of-work is valid and the result may be submitted.
9+
//!
10+
//! ## Pseudocode
11+
//! ```x
12+
//! u128 difficulty = 1_000_000;
13+
//! while true {
14+
//! u64 nonce = random_u64();
15+
//! u8[] block_hash = current_block_hash;
16+
//!
17+
//! // This should result in a byte array with size 64 (trim the end of key bytes if necessary)
18+
//! u8[] block_key_bytes = concat(block_hash, key_bytes);
19+
//! u8[] block_key_hash = keccak_256(block_key_bytes);
20+
//!
21+
//! // This should result in a byte array with size 40 (8 nonce bytes + 32 block_key_hash bytes)
22+
//! u8[] seal_bytes = concat(to_byte_array(nonce), block_key_hash);
23+
//! u8[] seal_hash = sha_256(keccak_256(seal_bytes));
24+
//!
25+
//! // Overflowing means that the multiplication result exceeded the max value possible for the type, u128 on this case.
26+
//! if overflows(as_u128(seal_hash) * difficulty) {
27+
//! // The seal hash doesn't meet the difficulty requirement, change the nonce and try again.
28+
//! continue;
29+
//! }
30+
//!
31+
//! // The generated seal hash meets the desired difficulty and may be submitted.
32+
//! }
33+
//! ```
734
835
use crate::Vec;
936
use crate::{AccountIdOf, BalanceOf};
@@ -22,25 +49,6 @@ use polkadot_sdk::{
2249

2350
const FAUCET_AMOUNT: u128 = 50_000_000_000_000_000_000;
2451

25-
/// Main execution function for the faucet pallet
26-
///
27-
/// This function processes a faucet request after it has passed the unsigned validation.
28-
/// It performs the following steps:
29-
/// 1. Ensures the account exists (or creates it)
30-
/// 2. Validates that the block number is recent (within the last 3 blocks)
31-
/// 3. Verifies that the proof-of-work meets the difficulty requirement
32-
/// 4. Checks that the submitted work hash matches the expected seal hash
33-
/// 5. Deposits tokens to the account if all checks pass
34-
///
35-
/// # Parameters
36-
/// * `key` - The account that will receive tokens
37-
/// * `block_number` - The block number used for the proof-of-work
38-
/// * `nonce` - The nonce value that makes the hash meet the difficulty
39-
/// * `work` - The hash result to verify
40-
///
41-
/// # Returns
42-
/// * `Ok(())` if successful
43-
/// * `Err` with an error if any check fails
4452
pub fn execute<T: crate::Config>(
4553
key: AccountIdOf<T>,
4654
block_number: u64,
@@ -54,7 +62,6 @@ pub fn execute<T: crate::Config>(
5462

5563
info!("do faucet with key: {key:?} and block number: {block_number} and nonce: {nonce} and hash: {work:?}");
5664

57-
// Get the current block number for validation
5865
let current_block_number: u64 = frame_system::Pallet::<T>::block_number()
5966
.try_into()
6067
.map_err(|_| "block number exceeded u64")?;
@@ -83,7 +90,7 @@ pub fn execute<T: crate::Config>(
8390
let seal: H256 = create_seal_hash::<T>(block_number, nonce, &key)?;
8491
ensure!(seal == work_hash, Error::<T>::InvalidSeal);
8592

86-
// Award tokens to the account (15 tokens with 18 decimals)
93+
// Award tokens to the account
8794
let amount: BalanceOf<T> = FAUCET_AMOUNT.try_into().map_err(|_| "Invalid amount")?;
8895
let _ = T::Currency::deposit_creating(&key, amount);
8996

@@ -99,14 +106,6 @@ pub fn execute<T: crate::Config>(
99106
/// This function combines a block hash with an account key and produces a new hash.
100107
/// It takes the 32-byte block hash and combines it with the first 32 bytes of the
101108
/// account ID to create a 64-byte array, then hashes it with keccak-256.
102-
///
103-
/// # Parameters
104-
/// * `block_hash_bytes` - The 32-byte hash of a block
105-
/// * `key` - The account ID to combine with the block hash
106-
///
107-
/// # Returns
108-
/// * `Ok(H256)` - The resulting hash if successful
109-
/// * `Err` - If the key is too small
110109
pub fn hash_block_and_key<T: crate::Config>(
111110
block_hash_bytes: &[u8; 32],
112111
key: &T::AccountId,
@@ -167,10 +166,6 @@ pub fn create_seal_hash<T: crate::Config>(
167166
Ok(seal_hash)
168167
}
169168

170-
/// Retrieves the hash of a block by its number
171-
///
172-
/// This function converts a u64 block number to the chain's BlockNumberFor type,
173-
/// retrieves the hash of that block from the system, and converts it to an H256 type.
174169
pub fn get_block_hash_from_u64<T: crate::Config>(block_number: u64) -> Result<H256, DispatchError> {
175170
let block_number: BlockNumberFor<T> = block_number.try_into().map_err(|_| {
176171
"Block number {block_number} is too large to be converted to BlockNumberFor<T>"

pallets/faucet/src/lib.rs

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,32 @@
11
//! # Faucet Pallet
22
//!
3-
//! A pallet that allows users to get test tokens on the testnet by performing proof-of-work.
4-
//!
53
//! ## Overview
64
//!
75
//! The Faucet pallet provides a mechanism for users to acquire test tokens on the testnet
8-
//! through a proof-of-work challenge. This enables developers to test their applications
9-
//! on the testnet without requiring real tokens.
6+
//! through a proof-of-work challenge. This enables developers to test their applications before
7+
//! deploying to the mainnet.
108
//!
119
//! The pallet is only enabled on testnets via the `testnet` feature flag and is disabled
1210
//! on production networks to prevent token generation outside of the normal emission schedule.
1311
//!
14-
//! ## Features
15-
//!
16-
//! - **Proof-of-Work**: Requires users to perform computational work to prevent abuse
17-
//! - **Token Distribution**: Provides a fixed amount of tokens to users who complete the challenge
18-
//! - **Rate Limiting**: Prevents wealthy accounts from repeatedly requesting tokens
19-
//! - **Recent Block Verification**: Ensures that proof-of-work was done recently
20-
//!
21-
//! ## Interface
12+
//! ## Usage
2213
//!
23-
//! ### Extrinsics
14+
//! ### Interface
2415
//!
25-
//! * `faucet` - Submit proof-of-work to receive test tokens
16+
//! A user-friendly interface can be found at https://wallet.testnet.torus.network.
2617
//!
27-
//! ## Usage
18+
//! ### Programatically
2819
//!
29-
//! To request tokens from the faucet, users need to:
20+
//! To request tokens programatically from the faucet, users need to:
3021
//!
3122
//! 1. Get the hash of a recent block (within the last 3 blocks)
3223
//! 2. Generate a proof-of-work based on block hash, account ID, and a nonce
3324
//! 3. Submit the proof to the faucet extrinsic
3425
//!
3526
//! If the proof is valid and the account's total balance (including staked tokens) is below
3627
//! the threshold, the account will receive the configured amount of test tokens.
28+
//!
29+
//! Details about the proof-of-work implementation can be found [here](crate::faucet).
3730
3831
#![cfg_attr(not(feature = "std"), no_std)]
3932
#![allow(unused)]

0 commit comments

Comments
 (0)