Skip to content

How Randomness Works

Roulette’s winning number is derived entirely on‑chain, so any player can reproduce and verify it after the fact.

1. Collecting entropy

When a player triggers spin(), the program grabs three fresh values:

SourceBytesWhy it matters
last_bettor_key32Prevents miners or validators from predicting the outcome; the final address is unknown until bets close.
current_time8Unix timestamp at the moment of the spin transaction.
current_slot8Solana slot index, changes every ~400 ms.

2. Hashing

The values are concatenated and hashed using Solana’s built‑in SHA‑256 helper:

rust
let hash_input_bytes: &[&[u8]] = &[
    &last_bettor_key.to_bytes()[..],
    &current_time.to_le_bytes()[..],
    &current_slot.to_le_bytes()[..],
];
let hash_result_obj = hash::hashv(hash_input_bytes);
let hash_bytes = hash_result_obj.to_bytes();

3. Truncation & modulo

rust
let hash_prefix_u64 = u64::from_le_bytes(hash_bytes[0..8].try_into().unwrap());
let winning_number = (hash_prefix_u64 % 37) as u8; // 0–36

By taking the first 8 bytes and applying mod 37, we map the 64‑bit value to the wheel’s 37 pockets (single zero layout).

4. Verifying a spin

  1. Open the spin transaction on Solscan.

  2. In the Log Messages tab, locate the program log:

    text
    Round 271 | Hash: [187, 12, 84… | Winning number: 17
  3. Reconstruct the input locally with the same last_bettor_key, current_time, and current_slot from the ledger entry.

  4. Run the above Rust snippet (or any SHA‑256 tool) — you should obtain the identical hash and number.

Unpredictable yet provable

Because the final bettor’s public key is unknown in advance, no validator can pre‑compute the hash. Yet, once the block is finalised, anyone can verify it step by step.