Proof of Stake (PoS)
Understanding Proof of Stake consensus mechanism used by modern blockchains.
Proof of Stake (PoS)
Proof of Stake is a consensus mechanism where validators are chosen based on the amount of cryptocurrency they "stake" (lock up) rather than computational work.
How PoS Works
- Staking: Validators lock up coins as stake
- Selection: Validator chosen based on stake amount and randomness
- Validation: Selected validator creates and validates block
- Rewards: Validator receives transaction fees
- Slashing: Malicious validators lose stake
Advantages over PoW
- Energy efficient: No mining required
- Faster: Blocks can be created quickly
- Scalable: Higher transaction throughput
- Lower barriers: No expensive mining hardware
Staking Structure
RUSTstruct Validator { address: String, stake: u64, // Amount staked is_active: bool, } struct StakingPool { validators: Vec<Validator>, total_stake: u64, }
Validator Selection
Validators are typically selected based on:
- Stake amount: More stake = higher chance
- Randomness: Prevents predictability
- Age: Some systems consider staking duration
Slashing
Validators who misbehave lose their stake:
- Double signing: Signing two conflicting blocks
- Downtime: Being offline too often
- Malicious behavior: Attempting attacks
PoS Variants
- Delegated PoS (DPoS): Stakeholders vote for delegates
- Liquid PoS: Staked tokens remain liquid
- Hybrid PoS: Combines PoS with other mechanisms
Ethereum 2.0
Ethereum moved from PoW to PoS:
- 32 ETH minimum stake
- Validators earn rewards
- More energy efficient
- Faster finality
Code Examples
Validator Structure
Creating validators and staking pool
struct Validator {
address: String,
stake: u64,
is_active: bool,
}
struct StakingPool {
validators: Vec<Validator>,
total_stake: u64,
}
impl StakingPool {
fn new() -> Self {
StakingPool {
validators: Vec::new(),
total_stake: 0,
}
}
fn add_validator(&mut self, validator: Validator) {
self.total_stake += validator.stake;
self.validators.push(validator);
}
fn select_validator(&self) -> Option<&Validator> {
self.validators.iter()
.filter(|v| v.is_active)
.max_by_key(|v| v.stake)
}
}
fn main() {
let mut pool = StakingPool::new();
pool.add_validator(Validator {
address: String::from("0xAlice"),
stake: 1000,
is_active: true,
});
pool.add_validator(Validator {
address: String::from("0xBob"),
stake: 2000,
is_active: true,
});
if let Some(validator) = pool.select_validator() {
println!("Selected validator: {} (stake: {})",
validator.address, validator.stake);
}
}Explanation:
In PoS, validators are selected based on their stake. Higher stake typically means higher chance of being selected, but randomness is also important.
Staking Mechanism
Staking and unstaking tokens
struct Validator {
address: String,
staked_amount: u64,
total_rewards: u64,
}
impl Validator {
fn stake(&mut self, amount: u64) {
self.staked_amount += amount;
println!("Staked {} tokens. Total stake: {}", amount, self.staked_amount);
}
fn unstake(&mut self, amount: u64) -> Result<(), String> {
if amount > self.staked_amount {
return Err(String::from("Cannot unstake more than staked"));
}
self.staked_amount -= amount;
println!("Unstaked {} tokens. Remaining stake: {}", amount, self.staked_amount);
Ok(())
}
fn add_reward(&mut self, reward: u64) {
self.total_rewards += reward;
}
}
fn main() {
let mut validator = Validator {
address: String::from("0xValidator1"),
staked_amount: 0,
total_rewards: 0,
};
validator.stake(1000);
validator.stake(500);
validator.add_reward(10);
validator.unstake(300).unwrap();
println!("Final stake: {}, Total rewards: {}",
validator.staked_amount, validator.total_rewards);
}Explanation:
Validators stake tokens to participate. They earn rewards for validating blocks and can unstake (after a waiting period in real systems).
Exercises
Create Validator
Create a validator and implement staking!
Starter Code:
struct Validator {
address: String,
stake: u64,
}
fn main() {
let mut validator = Validator {
address: String::from("0xMyValidator"),
stake: 0,
};
}