Distributed Randomness
RandomnessOn-chain verifiable randomness from the drand network, providing unpredictable and unbiasable random beacons for runtime logic.
Distributed Randomness Flow
Distributed Randomness
- Off-chain worker fetches drand pulse and submits write_pulse
- Governance updates beacon configuration via set_beacon_config
- Storage pruning via set_oldest_stored_round
Click items to navigate to their reference pages.
The Big Picture
Blockchains need randomness for fair selection, shuffling, and tie-breaking — but block producers can manipulate naive random number generators. The Drand pallet solves this by importing verifiable randomness from the drand network, a decentralized beacon run by dozens of independent organizations. Each pulse is a BLS signature that anyone can verify but nobody can predict or bias.
Why This Matters
Verifiable randomness is critical for fair neuron selection, registration tie-breaking, and any mechanism that needs unpredictable input. Without it, block producers could bias outcomes in their favor.
Example Scenario
Every ~30 seconds, drand produces a new randomness pulse. An off-chain worker fetches round 12345's pulse (a BLS signature) and submits it via write_pulse. The runtime verifies the signature against the stored BeaconConfig public key. If valid, the pulse is stored in Pulses[12345] and a NewPulse event is emitted. Other pallets can read Pulses to get unbiasable randomness.
Common Questions
- What is drand?
- drand (https://drand.love) is a distributed randomness beacon run by a consortium of organizations. It produces verifiable, unpredictable random values at regular intervals using threshold BLS signatures.
- Can a block producer manipulate the randomness?
- No — drand pulses are generated externally by a threshold of independent parties. A block producer can delay or omit a pulse, but cannot change its value. The runtime verifies authenticity via BLS signature verification.
- Why prune old pulses?
- Storing every pulse forever would consume unbounded storage. OldestStoredRound sets a retention window — only recent pulses are kept on-chain. Historical pulses can be verified off-chain from drand directly.
Use Cases
- Fair neuron selection for registration
- Randomized tie-breaking in consensus
- Verifiable shuffling for subnet assignments
- Building applications that need unbiasable randomness
The Drand pallet brings distributed randomness from the drand network onto Subtensor. Each round, an off-chain worker fetches the latest drand pulse — a BLS signature on the round number — and submits it to the chain via `write_pulse`. The pulse is verified on-chain against the drand beacon configuration before being stored.
Stored pulses in `Pulses` storage provide verifiable, unpredictable randomness that runtime logic can consume. The beacon configuration (`BeaconConfig`) stores the drand chain hash, public key, and genesis time, allowing the runtime to verify that each pulse is authentic.
Storage is bounded by `OldestStoredRound` — old pulses are pruned to prevent unbounded growth.
Triggers
- Off-chain worker fetches drand pulse and submits write_pulse
- Governance updates beacon configuration via set_beacon_config
- Storage pruning via set_oldest_stored_round
Inputs (4)
| Item | Type | Role |
|---|---|---|
| write_pulse Drand | call | Submit a verified drand randomness pulse |
| set_beacon_config Drand | call | Update the drand beacon verification parameters |
| set_oldest_stored_round Drand | call | Set the oldest round to keep (prunes older pulses) |
| BeaconConfig Drand | storage | Drand chain hash, public key, and genesis time for verification |
Outputs (6)
| Item | Type | Role |
|---|---|---|
| NewPulse Drand | event | Emitted when a new randomness pulse is stored |
| BeaconConfigChanged Drand | event | Emitted when the beacon configuration is updated |
| SetOldestStoredRound Drand | event | Emitted when the oldest stored round is updated (pruning) |
| Pulses Drand | storage | Stored randomness pulses indexed by round number |
| LastStoredRound Drand | storage | Most recent round number with a stored pulse |
| OldestStoredRound Drand | storage | Oldest round kept in storage (older rounds pruned) |
Source Files
pallets/drand/src/lib.rs