Skip to content

Instantly share code, notes, and snippets.

@rust-play
Created July 27, 2026 12:34
Show Gist options
  • Select an option

  • Save rust-play/1619e9f171715c5de980b936d2792cdc to your computer and use it in GitHub Desktop.

Select an option

Save rust-play/1619e9f171715c5de980b936d2792cdc to your computer and use it in GitHub Desktop.
Code shared from the Rust Playground
use std::time::{SystemTime, UNIX_EPOCH};
/// Simple Xorshift PRNG to maintain a 0-dependency standard library build.
struct Prng {
state: u32,
}
impl Prng {
fn new() -> Self {
let nanos = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.subsec_nanos();
Self {
state: if nanos == 0 { 1 } else { nanos }, // state must not be 0
}
}
/// Generates a random integer between min and max (inclusive).
fn gen_range(&mut self, min: u32, max: u32) -> u32 {
self.state ^= self.state << 13;
self.state ^= self.state >> 17;
self.state ^= self.state << 5;
min + (self.state % (max - min + 1))
}
}
/// Simulates the block header structure, focusing on the version bits used for signaling.
#[derive(Debug, Clone)]
pub struct BlockHeader {
pub height: u32,
pub version: i32,
pub previous_block_hash: String,
pub timestamp: u64,
}
impl BlockHeader {
/// Creates a new mock block header.
pub fn new(height: u32, version: i32, prev_hash: &str) -> Self {
BlockHeader {
height,
version,
previous_block_hash: prev_hash.to_string(),
timestamp: SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs(),
}
}
/// Checks if the block is signaling for the specific upgrade.
pub fn signals_upgrade(&self, bit: u8) -> bool {
let mask = 1 << bit;
(self.version & mask) != 0
}
}
/// Defines the consensus ruleset the node is running.
#[derive(Debug, Clone, PartialEq)]
pub enum NodeType {
/// Enforces the flag day (rejects non-signaling blocks).
UasfEnforcing,
/// Traditional node (accepts blocks regardless of signaling).
Legacy,
}
/// Defines the miner's political stance on the upgrade.
#[derive(Debug, Clone, PartialEq)]
pub enum MinerType {
/// Signals the required bit to activate the soft fork.
Compliant,
/// Refuses to signal the required bit, attempting to veto.
Defiant,
}
/// Represents a single fully validating node on the network.
pub struct Node {
pub id: String,
pub node_type: NodeType,
pub activation_height: u32,
pub required_signal_bit: u8,
pub local_chain: Vec<BlockHeader>,
}
impl Node {
pub fn new(
id: &str,
node_type: NodeType,
activation_height: u32,
required_signal_bit: u8,
genesis: BlockHeader,
) -> Self {
Node {
id: id.to_string(),
node_type,
activation_height,
required_signal_bit,
local_chain: vec![genesis],
}
}
/// Processes an incoming block based on local consensus rules.
pub fn process_block(&mut self, block: &BlockHeader) -> Result<(), String> {
let current_tip = self.local_chain.last().unwrap();
// 1. Basic validation (simulated height check to ensure it builds on our tip)
if block.height != current_tip.height + 1 {
return Err(format!(
"Invalid height. Expected {}, got {}",
current_tip.height + 1,
block.height
));
}
// 2. UASF Enforcement Logic (Only applies to UasfEnforcing nodes)
if self.node_type == NodeType::UasfEnforcing && block.height >= self.activation_height {
if !block.signals_upgrade(self.required_signal_bit) {
return Err(format!(
"UASF REJECTION: Failed to signal required bit {}.",
self.required_signal_bit
));
}
}
// Block is valid according to this node's ruleset.
self.local_chain.push(block.clone());
Ok(())
}
pub fn tip_hash(&self) -> &str {
&self.local_chain.last().unwrap().previous_block_hash
}
}
/// Represents the P2P network broadcasting blocks to all connected nodes.
pub struct Network {
pub nodes: Vec<Node>,
}
impl Network {
pub fn new() -> Self {
Network { nodes: Vec::new() }
}
pub fn add_node(&mut self, node: Node) {
self.nodes.push(node);
}
/// Broadcasts a mined block to all nodes and prints their individual consensus decisions.
pub fn broadcast_block(&mut self, block: &BlockHeader) {
println!(
"\n[NETWORK] Broadcasting Block {} (Version: {:#010X})",
block.height, block.version
);
let mut uasf_accepted = 0;
let mut legacy_accepted = 0;
for node in self.nodes.iter_mut() {
match node.process_block(block) {
Ok(_) => {
println!(" [✓] Node {} ({:?}) accepted.", node.id, node.node_type);
if node.node_type == NodeType::UasfEnforcing {
uasf_accepted += 1;
} else {
legacy_accepted += 1;
}
}
Err(e) => {
println!(
" [✗] Node {} ({:?}) rejected: {}",
node.id, node.node_type, e
);
}
}
}
self.print_network_state(uasf_accepted, legacy_accepted);
}
/// Analyzes if the network has split into multiple distinct chains.
fn print_network_state(&self, uasf_accepted: usize, legacy_accepted: usize) {
let total_uasf = self
.nodes
.iter()
.filter(|n| n.node_type == NodeType::UasfEnforcing)
.count();
let total_legacy = self
.nodes
.iter()
.filter(|n| n.node_type == NodeType::Legacy)
.count();
println!(
" => Status: UASF Nodes ({}/{}), Legacy Nodes ({}/{})",
uasf_accepted, total_uasf, legacy_accepted, total_legacy
);
if uasf_accepted == 0 && legacy_accepted > 0 && total_uasf > 0 {
println!(" [!] WARNING: CHAIN SPLIT DETECTED. Network consensus has fractured.");
} else if uasf_accepted > 0 && legacy_accepted > 0 {
println!(" [✓] CONSENSUS MAINTAINED. All nodes are on the same chain.");
}
}
}
fn main() {
let mut prng = Prng::new();
let activation_height = 100;
let required_bit = 1;
let genesis = BlockHeader::new(98, 0x20000000, "00000000000000000000000000000000");
for iteration in 1..=100 {
println!("\n=======================================================");
println!("--- SIMULATION ITERATION {} ---", iteration);
println!("=======================================================");
let mut network = Network::new();
// 1. Randomize Node Distribution
let num_uasf = prng.gen_range(1, 10);
let num_legacy = prng.gen_range(1, 10);
println!(
"Initializing network with {} UASF nodes and {} Legacy nodes.",
num_uasf, num_legacy
);
println!("UASF Flag Day configured for Block Height {}.", activation_height);
for i in 0..num_uasf {
network.add_node(Node::new(
&format!("UASF_Node_{}", i),
NodeType::UasfEnforcing,
activation_height,
required_bit,
genesis.clone(),
));
}
for i in 0..num_legacy {
network.add_node(Node::new(
&format!("Legacy_Node_{}", i),
NodeType::Legacy,
activation_height,
required_bit,
genesis.clone(),
));
}
// 2. Randomize Miner Hash Power Distribution
let num_compliant_miners = prng.gen_range(1, 10);
let num_defiant_miners = prng.gen_range(1, 10);
let mut miners = Vec::new();
for _ in 0..num_compliant_miners { miners.push(MinerType::Compliant); }
for _ in 0..num_defiant_miners { miners.push(MinerType::Defiant); }
println!(
"Hash power distribution: {} Compliant Miners, {} Defiant Miners.",
num_compliant_miners, num_defiant_miners
);
// Block 99: Pre-activation. No signal required.
println!("\n--- Mining Block 99 (Pre-Activation) ---");
let block_99 = BlockHeader::new(99, 0x20000000, "hash98");
network.broadcast_block(&block_99);
// Block 100: The Flag Day. A random miner wins the block.
let winning_miner_idx = prng.gen_range(0, miners.len() as u32 - 1) as usize;
let winning_miner = &miners[winning_miner_idx];
println!("\n--- Mining Block 100 (Activation Boundary) ---");
println!("A {:?} miner won the proof-of-work race for Block 100.", winning_miner);
let mut block_100_version = 0x20000000;
if *winning_miner == MinerType::Compliant {
// Compliant miner flips the required bit
block_100_version |= 1 << required_bit;
} // Defiant miner leaves it unset
let block_100 = BlockHeader::new(100, block_100_version, "hash99");
network.broadcast_block(&block_100);
// Iteration concludes, showcasing the immediate split or success based on who mined the block.
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment