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
StakingActiveflag - Stop staking when limit is reached
3. Custom Data Types¶
VividStakingState: Vivid staking state- Extended
Exposurewith 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, errorsimpls.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.