Created
June 9, 2025 10:10
-
-
Save brunopgalvao/f3c6d4330e1a4ed2e2edbc05d216923a to your computer and use it in GitHub Desktop.
ProofOfStakeBlockchain example
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use sha2::{Sha256, Digest}; | |
// A single block in our proof-of-stake blockchain | |
#[derive(Debug, Clone)] | |
struct Block { | |
index: u64, // Position in the chain (0, 1, 2, ...) | |
data: String, // The actual data/transactions | |
previous_hash: String, // Hash of the previous block | |
hash: String, // This block's unique identifier | |
validator: String, // Address of the validator who created this block | |
stake_proof: u64, // Proof that validator had required stake | |
} | |
impl Block { | |
// Create a new block (constructor) - validator creates without mining | |
fn new(index: u64, data: String, previous_hash: String, validator: String, stake_proof: u64) -> Block { | |
let mut block = Block { | |
index, | |
data, | |
previous_hash, | |
hash: String::new(), | |
validator, | |
stake_proof, | |
}; | |
// Calculate the hash for this block - no mining required! | |
block.hash = block.calculate_hash(); | |
block | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::collections::HashMap; | |
// The proof-of-stake blockchain - manages both blocks and validators | |
struct ProofOfStakeBlockchain { | |
chain: Vec<Block>, | |
validators: HashMap<String, Validator>, | |
minimum_stake: u64, // Minimum stake required to become a validator | |
current_epoch: u64, // Current time period for validator selection | |
} | |
impl ProofOfStakeBlockchain { | |
// Create a new proof-of-stake blockchain with genesis block | |
fn new(minimum_stake: u64) -> ProofOfStakeBlockchain { | |
let mut blockchain = ProofOfStakeBlockchain { | |
chain: Vec::new(), | |
validators: HashMap::new(), | |
minimum_stake, | |
current_epoch: 0, | |
}; | |
// Create the genesis block with a bootstrap validator | |
blockchain.create_genesis_block(); | |
blockchain | |
} | |
fn create_genesis_block(&mut self) { | |
// Bootstrap validator for the genesis block | |
let genesis_validator = "genesis_validator".to_string(); | |
self.validators.insert(genesis_validator.clone(), Validator { | |
address: genesis_validator.clone(), | |
stake: self.minimum_stake, | |
is_active: true, | |
}); | |
let genesis = Block::new( | |
0, | |
"Genesis Block".to_string(), | |
"0".to_string(), | |
genesis_validator, | |
self.minimum_stake | |
); | |
self.chain.push(genesis); | |
} | |
// Register a new validator with their stake | |
fn register_validator(&mut self, address: String, stake_amount: u64) -> Result<(), String> { | |
if stake_amount < self.minimum_stake { | |
return Err(format!("Minimum stake required: {}", self.minimum_stake)); | |
} | |
let validator = Validator { | |
address: address.clone(), | |
stake: stake_amount, | |
is_active: true, | |
}; | |
self.validators.insert(address, validator); | |
Ok(()) | |
} | |
// Create and add a new block using proof of stake consensus | |
fn create_block(&mut self, data: String) -> Result<(), String> { | |
// Select validator for this block based on their stake | |
let selected_validator = select_validator(&self.validators) | |
.ok_or("No eligible validators available")?; | |
let previous_block = self.chain.last().unwrap(); | |
let validator_stake = self.validators[&selected_validator].stake; | |
let new_block = Block::new( | |
previous_block.index + 1, | |
data, | |
previous_block.hash.clone(), | |
selected_validator.clone(), | |
validator_stake | |
); | |
// Verify the block meets proof of stake requirements | |
if new_block.validate_stake_proof(&self.validators) { | |
self.chain.push(new_block); | |
println!("Block created by validator: {}", selected_validator); | |
Ok(()) | |
} else { | |
Err("Invalid stake proof for selected validator".to_string()) | |
} | |
} | |
// Verify the entire blockchain's integrity | |
fn is_chain_valid(&self) -> bool { | |
for i in 1..self.chain.len() { | |
let current_block = &self.chain[i]; | |
let previous_block = &self.chain[i - 1]; | |
// Check if the current block's hash is valid | |
if current_block.hash != current_block.calculate_hash() { | |
return false; | |
} | |
// Check if the current block properly references the previous block | |
if current_block.previous_hash != previous_block.hash { | |
return false; | |
} | |
// Check if the validator had sufficient stake when creating the block | |
if !current_block.validate_stake_proof(&self.validators) { | |
return false; | |
} | |
} | |
true | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::collections::HashMap; | |
use rand::Rng; | |
// Validator information in our proof-of-stake system | |
#[derive(Debug, Clone)] | |
struct Validator { | |
address: String, // Unique identifier for this validator | |
stake: u64, // Amount of cryptocurrency they've staked | |
is_active: bool, // Whether they're eligible to validate | |
} | |
impl Block { | |
// Calculate the cryptographic hash for this block | |
fn calculate_hash(&self) -> String { | |
let input = format!( | |
"{}{}{}{}{}", | |
self.index, | |
&self.data, | |
&self.previous_hash, | |
&self.validator, | |
self.stake_proof | |
); | |
// Use SHA-256 to create a unique hash - no mining loops needed | |
let mut hasher = Sha256::new(); | |
hasher.update(input.as_bytes()); | |
format!("{:x}", hasher.finalize()) | |
} | |
// Validate that the block creator had sufficient stake | |
fn validate_stake_proof(&self, validators: &HashMap<String, Validator>) -> bool { | |
if let Some(validator) = validators.get(&self.validator) { | |
// Check if validator is active and has minimum required stake | |
validator.is_active && validator.stake >= self.stake_proof | |
} else { | |
false // Validator not found in the registry | |
} | |
} | |
} | |
// Function to select the next validator (simplified selection algorithm) | |
fn select_validator(validators: &HashMap<String, Validator>) -> Option<String> { | |
let active_validators: Vec<_> = validators | |
.iter() | |
.filter(|(_, v)| v.is_active && v.stake > 0) | |
.collect(); | |
if active_validators.is_empty() { | |
return None; | |
} | |
// Simple weighted random selection based on stake | |
let total_stake: u64 = active_validators.iter().map(|(_, v)| v.stake).sum(); | |
let mut rng = rand::thread_rng(); | |
let random_point = rng.gen_range(0..total_stake); | |
let mut cumulative_stake = 0; | |
for (address, validator) in active_validators { | |
cumulative_stake += validator.stake; | |
if random_point < cumulative_stake { | |
return Some(address.clone()); | |
} | |
} | |
None // This should never happen if logic is correct | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment