Want to run VRF end to end on your machine? Use the Local Validator Setup guide for the fully local stack, the Surfpool alternative, and the local vrf-oracle flow.
Any Solana program can request and consume verifiable randomness onchain within seconds using the MagicBlock VRF SDK. By the end of this guide, you’ll have a working example that rolls a dice using verifiable randomness.
Add ephemeral_vrf_sdk with Anchor features to your program
cargo add ephemeral_vrf_sdk --features anchor
Import vrf , create_request_randomness_ix, RequestRandomnessParams, and SerializableAccountMeta:
use ephemeral_vrf_sdk::anchor::vrf;use ephemeral_vrf_sdk::instructions::{create_request_randomness_ix, RequestRandomnessParams};use ephemeral_vrf_sdk::types::SerializableAccountMeta;
Add instructions roll_dice to request randomness and callback_roll_dice to consume randomness, along with its context:
#[program]pub mod random_dice { use super::*; // ... `initialize` instruction // Request Randomness pub fn roll_dice(ctx: Context<DoRollDiceCtx>, client_seed: u8) -> Result<()> { msg!("Requesting randomness..."); let ix = create_request_randomness_ix(RequestRandomnessParams { payer: ctx.accounts.payer.key(), oracle_queue: ctx.accounts.oracle_queue.key(), callback_program_id: ID, callback_discriminator: instruction::CallbackRollDice::DISCRIMINATOR.to_vec(), caller_seed: [client_seed; 32], // Specify any account that is required by the callback accounts_metas: Some(vec![SerializableAccountMeta { pubkey: ctx.accounts.player.key(), is_signer: false, is_writable: true, }]), ..Default::default() }); ctx.accounts .invoke_signed_vrf(&ctx.accounts.payer.to_account_info(), &ix)?; Ok(()) } // Consume Randomness pub fn callback_roll_dice( ctx: Context<CallbackRollDiceCtx>, randomness: [u8; 32], ) -> Result<()> { let rnd_u8 = ephemeral_vrf_sdk::rnd::random_u8_with_range(&randomness, 1, 6); msg!("Consuming random number: {:?}", rnd_u8); let player = &mut ctx.accounts.player; player.last_result = rnd_u8; // Update the player's last result Ok(()) }}#[vrf]#[derive(Accounts)]pub struct DoRollDiceCtx<'info> { #[account(mut)] pub payer: Signer<'info>, #[account(seeds = [PLAYER, payer.key().to_bytes().as_slice()], bump)] pub player: Account<'info, Player>, /// CHECK: The oracle queue #[account(mut, address = ephemeral_vrf_sdk::consts::DEFAULT_QUEUE)] pub oracle_queue: AccountInfo<'info>,}#[derive(Accounts)]pub struct CallbackRollDiceCtx<'info> { /// This check ensure that the vrf_program_identity (which is a PDA) is a singer /// enforcing the callback is executed by the VRF program trough CPI #[account(address = ephemeral_vrf_sdk::consts::VRF_PROGRAM_IDENTITY)] pub vrf_program_identity: Signer<'info>, #[account(mut)] pub player: Account<'info, Player>,}// ... Other context and account struct.
Request Randomness is the process of generating a random hashId with the relevant callback instruction for the verified oracles to be triggered.
Consume Randomness is the process of using the verifiable randomness by your program which is provided and triggered through verified oracle.