Staking Pallet Analysis

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 = StorageMap<_, Twox64Concat, T::AccountId, T::AccountId>;
pub type Ledger = StorageMap<_, Blake2_128Concat, T::AccountId, StakingLedger>;
pub type Payee = StorageMap<_, Twox64Concat, T::AccountId, RewardDestination>;

Validators and Nominators:

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

Eras and Their Data:

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

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 {
    pub stash: T::AccountId,           // Stash account
    pub total: BalanceOf,          // Total balance
    pub active: BalanceOf,         // Active balance
    pub unlocking: BoundedVec>, T::MaxUnlockingChunks>,
    pub claimed_rewards: BoundedVec,
    pub vivid_staking: Option,
    pub controller: Option,
}

Exposure:

pub struct Exposure {
    pub total: Balance,                // Total exposure
    pub own: Balance,                  // Own exposure
    pub others: Vec>,
    pub vivid_staking: Option,
}

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) -> 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> {
    // Iterate through VoterList
    // Filter by weight
    // Apply bounds constraints
}

Getting Targets:

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

2.4 Session Management

SessionManager Implementation:

impl pallet_session::SessionManager for Pallet {
    fn new_session(new_index: SessionIndex) -> Option> {
        // 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) -> u32 {
    T::NominationsQuota::get_quota(balance)
}

pub fn api_estimate_staking_payout(account: T::AccountId) -> BalanceOf {
    // 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.