Skip to content

Staking Pallet Analysis: mod.rs and impls.rs

Overview

The Staking pallet is a key component of the Proof-of-Stake system in Taler blockchain. It manages staking, validation, nomination and reward distribution.

File Structure

1. mod.rs - Main Pallet Structure

1.1 Imports and Dependencies

use frame_election_provider_support::{ElectionProvider, ElectionProviderBase, SortedListProvider, VoteWeight};
use frame_support::{pallet_prelude::*, traits::{Currency, Defensive, EnsureOrigin, ...}};
use sp_staking::{EraIndex, SessionIndex, StakingAccount};

1.2 Pallet Configuration (Config trait)

Main configuration types:

Currency Types: - Currency: Main currency for staking (LockableCurrency) - CurrencyBalance: Balance type (AtLeast32BitUnsigned + additional traits) - CurrencyToVote: Balance to vote conversion for elections

Time Parameters: - UnixTime: Time for calculating era duration - SessionsPerEra: Number of sessions per era - BondingDuration: Bonding duration (in eras) - SlashDeferDuration: Deferred slash application

Economic Parameters: - IssuanceLimit: Token issuance limit - StandartStakingInterest: Standard staking interest rate - VividStakingInterestPerMonth: Additional rate for locked months

System Components: - ElectionProvider: Validator election provider - VoterList: List of voters (nominators) - TargetList: List of targets (validators) - SessionInterface: Interface for session management

1.3 Storage (Data Storage)

Main Accounts:

pub type Bonded<T: Config> = StorageMap<_, Twox64Concat, T::AccountId, T::AccountId>;
pub type Ledger<T: Config> = StorageMap<_, Blake2_128Concat, T::AccountId, StakingLedger<T>>;
pub type Payee<T: Config> = StorageMap<_, Twox64Concat, T::AccountId, RewardDestination<T::AccountId>>;

Validators and Nominators:

pub type Validators<T: Config> = CountedStorageMap<_, Twox64Concat, T::AccountId, ValidatorPrefs>;
pub type Nominators<T: Config> = CountedStorageMap<_, Twox64Concat, T::AccountId, Nominations<T>>;

Eras and Their Data:

pub type CurrentEra<T> = StorageValue<_, EraIndex>;
pub type ActiveEra<T> = StorageValue<_, ActiveEraInfo>;
pub type ErasStakers<T: Config> = StorageDoubleMap<_, Twox64Concat, EraIndex, Twox64Concat, T::AccountId, Exposure<T::AccountId, BalanceOf<T>>>;
pub type ErasRewardPoints<T: Config> = StorageMap<_, Twox64Concat, EraIndex, EraRewardPoints<T::AccountId>>;

1.4 Events

Key pallet events: - EraPaid: Era payout - Rewarded: Nominator/validator reward - Slashed: Staker slash - Bonded: Bonding funds - Unbonded: Unbonding funds - StakersElected: New stakers election - VividStakingScheduled: Vivid staking scheduling - VividStakingCancelled: Vivid staking cancellation

1.5 Errors

Main error types: - NotController/NotStash: Wrong account type - AlreadyBonded/AlreadyPaired: Already linked accounts - InsufficientBond: Insufficient bond - InvalidEraToReward: Invalid era for reward - VividStakingInProgress: Vivid staking in progress

1.6 Dispatchable Functions

Main Staking Operations: - bond(): Bonding funds for staking - bond_extra(): Additional bonding - unbond(): Unbonding funds - withdraw_unbonded(): Withdrawing unbonded funds - rebond(): Re-bonding

Vivid Staking: - vivid(): Activate vivid staking for N months - unvivid(): Cancel vivid staking

Validation and Nomination: - validate(): Become validator - nominate(): Nominate validators - chill(): Stop participation

Administrative Functions: - set_validator_count(): Set validator count - force_new_era(): Force start new era - set_invulnerables(): Set invulnerable validators

2. impls.rs - Logic Implementation

2.1 Main Data Structures

StakingLedger:

pub struct StakingLedger<T: Config> {
    pub stash: T::AccountId,           // Stash account
    pub total: BalanceOf<T>,          // Total balance
    pub active: BalanceOf<T>,         // Active balance
    pub unlocking: BoundedVec<UnlockChunk<BalanceOf<T>>, T::MaxUnlockingChunks>,
    pub claimed_rewards: BoundedVec<EraIndex, T::HistoryDepth>,
    pub vivid_staking: Option<VividStakingState>,
    pub controller: Option<T::AccountId>,
}

Exposure:

pub struct Exposure<AccountId, Balance: HasCompact> {
    pub total: Balance,                // Total exposure
    pub own: Balance,                  // Own exposure
    pub others: Vec<IndividualExposure<AccountId, Balance>>,
    pub vivid_staking: Option<VividStakingState>,
}

2.2 Key Functions

Ledger Management: - ledger(): Get account ledger - bonded(): Get stash account controller - slashable_balance_of(): Get slashable balance

Interest Calculation:

fn calculate_interest(era: EraIndex, opt_vivid_staking: &Option<VividStakingState>) -> Perbill {
    if let Some(vivid_staking) = opt_vivid_staking {
        if vivid_staking.starting_era <= era && vivid_staking.ending_era >= era {
            let eras_count = vivid_staking.ending_era.saturating_sub(vivid_staking.starting_era.saturating_sub(1));
            let months_count = eras_count / 28;
            return T::StandartStakingInterest::get() + 
                   Perbill::from_parts(T::VividStakingInterestPerMonth::get().deconstruct() * months_count);
        }
    }
    T::StandartStakingInterest::get()
}

Reward Payout: - do_payout_stakers(): Main reward payout logic - make_payout(): Create payout considering destination - Interest calculation for validators and nominators

Era Management: - new_session(): Plan new session - start_session(): Start session - end_session(): End session - trigger_new_era(): Trigger new era

2.3 Election Provider Implementation

Getting Voters:

pub fn get_npos_voters(bounds: DataProviderBounds) -> Vec<VoterOf<Self>> {
    // Iterate through VoterList
    // Filter by weight
    // Apply bounds constraints
}

Getting Targets:

pub fn get_npos_targets(bounds: DataProviderBounds) -> Vec<T::AccountId> {
    // Iterate through TargetList
    // Validate targets
}

2.4 Session Management

SessionManager Implementation:

impl<T: Config> pallet_session::SessionManager<T::AccountId> for Pallet<T> {
    fn new_session(new_index: SessionIndex) -> Option<Vec<T::AccountId>> {
        // Plan new session
        // Return new validator set
    }

    fn start_session(start_index: SessionIndex) {
        // Start session
        // Update active era
    }

    fn end_session(end_index: SessionIndex) {
        // End session
        // Handle era completion
    }
}

2.5 StakingInterface Implementation

Main Interface Methods: - minimum_nominator_bond(): Minimum nominator bond - minimum_validator_bond(): Minimum validator bond - desired_validator_count(): Desired validator count - election_ongoing(): Check for active elections - force_unstake(): Force unstaking - stake(): Get stake information

2.6 Runtime API

API for External Calls:

pub fn api_nominations_quota(balance: BalanceOf<T>) -> u32 {
    T::NominationsQuota::get_quota(balance)
}

pub fn api_estimate_staking_payout(account: T::AccountId) -> BalanceOf<T> {
    // Calculate expected payout for account
    // Consider vivid staking
    // Calculate interest
}

Taler Staking Features

1. Vivid Staking

  • Additional interest for long-term locking
  • Parameters: starting_era, ending_era
  • Calculation: StandartStakingInterest + VividStakingInterestPerMonth * months

2. Issuance Limits

  • IssuanceLimit: Maximum token issuance
  • Control through StakingActive flag
  • Stop staking when limit is reached

3. Custom Data Types

  • VividStakingState: Vivid staking state
  • Extended Exposure with vivid support
  • Special events for vivid operations

4. Economic Model

  • Base rate: StandartStakingInterest
  • Additional rate: VividStakingInterestPerMonth * months
  • Issuance limit: IssuanceLimit
  • Control through StakingActive

Architectural Decisions

1. Separation of Concerns

  • mod.rs: Structure, configuration, events, errors
  • impls.rs: Business logic, algorithms, interfaces

2. Modularity

  • Separate modules for slashing, weights, benchmarking
  • Clear separation of storage, events, errors

3. Performance

  • Optimized storage operations
  • BoundedVec for size limitations
  • Efficient election algorithms

4. Security

  • Checks at all levels
  • Defensive programming
  • Input data validation

Conclusion

The Staking pallet is a complex Proof-of-Stake management system with support for: - Standard staking - Vivid staking with additional interest - Flexible reward system - Administrative management - Runtime API for external integrations

The architecture provides high performance, security and scalability of the staking system.