Skip to content

The Randomness Pallet

Introduction

Moonbeam utilizes verifiable random functions (VRF) to generate randomness that can be verified on-chain. A VRF is a cryptographic function that takes some input and produces random values, along with a proof of authenticity that these random values were generated by the submitter. The proof can be verified by anyone to ensure the random values generated were calculated correctly. For more information on Moonbeam's on-chain randomness, such as an overview on the randomness sources, the request and fulfill cycle, and more, please refer to the Randomness on Moonbeam overview page.

The randomness pallet enables you to check on randomness requests that have not been fulfilled or purged, randomness results, and more. To actually request and fulfill randomness, you can use the randomness precompile and randomness consumer contracts. The precompile is a Solidity interface that enables you to request randomness, check on the status of requests, fulfill requests, and more through the Ethereum API. For more information on how to use both of these contracts, please refer to the Randomness Precompile guide.

This page will provide an overview of the storage methods and getters for the pallet constants available in the randomness pallet.

Randomness Pallet Interface

Storage Methods

The randomness pallet includes the following read-only storage methods to obtain chain state data:

localVrfOutput() - returns the current local per-block VRF randomness

None

H256 - A 32-byte (256-bit) hex value, starting with "0x"`

import { ApiPromise, WsProvider } from '@polkadot/api';

const main = async () => {
  // Initialize the API
  const api = await ApiPromise.create({
    provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
  });

  try {
    // Get the local VRF output from randomness pallet
    const localVrf = await api.query.randomness.localVrfOutput();

    console.log('Local VRF Output:', localVrf.toString());

    process.exit(0);
  } catch (error) {
    console.error('Error querying local VRF output:', error);
    process.exit(1);
  }
};

// Execute the script
main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});
palletVersion() - returns the current pallet version

None

u16 - The pallet version

import { ApiPromise, WsProvider } from '@polkadot/api';

const main = async () => {
  // Initialize the API
  const api = await ApiPromise.create({
    provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
  });

  try {
    // Get the pallet version from randomness pallet
    const version = await api.query.randomness.palletVersion();

    console.log('Randomness Pallet Version:', version.toString());

    process.exit(0);
  } catch (error) {
    console.error('Error querying randomness pallet version:', error);
    process.exit(1);
  }
};

// Execute the script
main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});
randomnessResults(PalletRandomnessRequestType) - snapshot of randomness to fulfill all requests that are for the same raw randomness
  • PalletRandomnessRequestType - You can optionally provide the type of randomness you'd like, e.g. Local or BabeEpoch Randomness. If you omit this, you'll receive all types of randomness.

The query returns mappings of request types to their randomness outcomes, where:

  1. Key: Identifies the source and timing of the randomness request. e.g. { Local: '4,619,640' } indicates this was a Local randomness request from block number 4,619,640. The Local type uses block numbers as identifiers, while BabeEpoch uses epoch numbers.

  2. Value: Contains two pieces of information, including randomness: A 32-byte hex string (0x15b5f6...c816) representing the random value generated and requestCount: The number of requests that used this same random value (e.g. '1')

Multiple requests for randomness at the same block/epoch would share the same random value, which is why there's a requestCount field.

import { ApiPromise, WsProvider } from '@polkadot/api';

const main = async () => {
  // Initialize the API
  const api = await ApiPromise.create({
    provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
  });

  try {
    // Query Babe Epoch randomness results
    const babeResults = await api.query.randomness.randomnessResults({
      BabeEpoch: 0,
    });
    console.log('\nBabe Epoch Randomness Results:');
    console.log(babeResults.toHuman());

    // Query Local randomness results
    const localResults = await api.query.randomness.randomnessResults({
      Local: 0,
    });
    console.log('\nLocal Randomness Results:');
    console.log(localResults.toHuman());

    // Get the available keys/entries
    console.log('\nAll Available Randomness Results:');
    const entries = await api.query.randomness.randomnessResults.entries();
    entries.forEach(([key, value]) => {
      console.log(
        'Key:',
        key.args.map((k) => k.toHuman())
      );
      console.log('Value:', value.toHuman());
      console.log('---');
    });

    process.exit(0);
  } catch (error) {
    console.error('Error querying randomness results:', error);
    process.exit(1);
  }
};

// Execute the script
main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});
relayEpoch() - returns the relay epoch

None

u64 - the relay epoch

import { ApiPromise, WsProvider } from '@polkadot/api';

const main = async () => {
  // Initialize the API
  const api = await ApiPromise.create({
    provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
  });

  try {
    // Get the relay epoch
    const relayEpoch = await api.query.randomness.relayEpoch();

    console.log('Current Relay Epoch:', relayEpoch.toString());

    process.exit(0);
  } catch (error) {
    console.error('Error querying relay epoch:', error);
    process.exit(1);
  }
};

// Execute the script
main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});
requestCount() - returns the number of randomness requests made so far, and is used to generate the next request's uid

None

u64 - the request count

import { ApiPromise, WsProvider } from '@polkadot/api';

const main = async () => {
  // Initialize the API
  const api = await ApiPromise.create({
    provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
  });

  try {
    // Get the request count
    const requestCount = await api.query.randomness.requestCount();

    console.log('Total Randomness Requests:', requestCount.toString());
    console.log(
      'Next Request UID will be:',
      (Number(requestCount) + 1).toString()
    );

    process.exit(0);
  } catch (error) {
    console.error('Error querying request count:', error);
    process.exit(1);
  }
};

// Execute the script
main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});
requests(u64) - returns a given randomness request or all of the randomness requests that have not been fulfilled nor purged yet
  • u64 - The request ID number (optional)

Returns an Option containing the request information if it exists and hasn't been fulfilled/purged, including:

  • The request type (Local or Babe)
  • When it can be fulfilled
  • Number of random words requested
  • The requester's information
import { ApiPromise, WsProvider } from '@polkadot/api';

const main = async () => {
  // Initialize the API
  const api = await ApiPromise.create({
    provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
  });

  try {
    // First get the current request count
    const requestCount = await api.query.randomness.requestCount();
    console.log('Total Request Count:', requestCount.toString());

    // Query most recent request as an example
    if (requestCount > 0) {
      const latestRequestId = requestCount - 1;
      const specificRequest =
        await api.query.randomness.requests(latestRequestId);

      console.log('\nLatest Request (ID:', latestRequestId.toString(), '):');
      if (specificRequest.isSome) {
        console.log(specificRequest.unwrap().toHuman());
      } else {
        console.log('Request has been fulfilled or purged');
      }
    }

    // Query all available requests
    console.log('\nAll Pending Requests:');
    const allRequests = await api.query.randomness.requests.entries();

    if (allRequests.length === 0) {
      console.log('No pending requests found');
    } else {
      allRequests.forEach(([key, value]) => {
        const requestId = key.args[0].toString();
        console.log('\nRequest ID:', requestId);
        if (value.isSome) {
          const request = value.unwrap();
          console.log('Request Details:', request.toHuman());
        }
      });

      // Show some statistics
      console.log('\nRequest Statistics:');
      console.log('Total Pending Requests:', allRequests.length);
    }

    process.exit(0);
  } catch (error) {
    console.error('Error querying randomness requests:', error);
    process.exit(1);
  }
};

// Execute the script
main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});

Pallet Constants

The randomness pallet includes the following read-only functions to obtain pallet constants:

blockExpirationDelay() - the number of blocks that must pass before a local VRF request expires and can be purged

None

u32 - the number of blocks that must pass before a local VRF request expires and can be purged

import { ApiPromise, WsProvider } from '@polkadot/api';

const main = async () => {
  // Initialize the API
  const api = await ApiPromise.create({
    provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
  });

  try {
    // Get the block expiration delay constant
    const blockExpirationDelay =
      await api.consts.randomness.blockExpirationDelay;

    console.log(
      'Block Expiration Delay:',
      blockExpirationDelay.toString(),
      'blocks'
    );

    process.exit(0);
  } catch (error) {
    console.error('Error querying block expiration delay:', error);
    process.exit(1);
  }
};

// Execute the script
main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});
deposit() - the amount that should be taken as a security deposit when requesting random words. There is one deposit per request

None

u128 - the amount that should be taken as a security deposit when requesting random words

import { ApiPromise, WsProvider } from '@polkadot/api';

const main = async () => {
  // Initialize the API
  const api = await ApiPromise.create({
    provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
  });

  try {
    // Get the deposit constant
    const deposit = await api.consts.randomness.deposit;

    console.log('Randomness Request Deposit:', deposit.toString(), 'Wei');
    console.log(
      'Deposit in DEV:',
      (BigInt(deposit) / BigInt(10 ** 18)).toString()
    );

    process.exit(0);
  } catch (error) {
    console.error('Error querying randomness deposit:', error);
    process.exit(1);
  }
};

// Execute the script
main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});
epochExpirationDelay() - the number of epochs that must pass before a BABE request expires and can be purged

None

u64 - the number of epochs that must pass before a BABE request expires and can be purged

import { ApiPromise, WsProvider } from '@polkadot/api';

const main = async () => {
  // Initialize the API
  const api = await ApiPromise.create({
    provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
  });

  try {
    // Get the epoch expiration delay constant
    const epochExpirationDelay =
      await api.consts.randomness.epochExpirationDelay;

    console.log(
      'Epoch Expiration Delay:',
      epochExpirationDelay.toString(),
      'epochs'
    );

    process.exit(0);
  } catch (error) {
    console.error('Error querying epoch expiration delay:', error);
    process.exit(1);
  }
};

// Execute the script
main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});
maxBlockDelay() - the maximum number of blocks (after the block in which the request was made) that can pass before a local VRF request is fulfilled

None

u32 - the maximum number of blocks that can pass before a local VRF request is fulfilled

import { ApiPromise, WsProvider } from '@polkadot/api';

const main = async () => {
  // Initialize the API
  const api = await ApiPromise.create({
    provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
  });

  try {
    // Get the maximum block delay constant
    const maxBlockDelay = await api.consts.randomness.maxBlockDelay;

    console.log('Maximum Block Delay:', maxBlockDelay.toString(), 'blocks');

    process.exit(0);
  } catch (error) {
    console.error('Error querying max block delay:', error);
    process.exit(1);
  }
};

// Execute the script
main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});
maxRandomWords() - the maximum number of random words that can be requested

None

u8 - the maximum number of random words that can be requested

import { ApiPromise, WsProvider } from '@polkadot/api';

const main = async () => {
  // Initialize the API
  const api = await ApiPromise.create({
    provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
  });

  try {
    // Get the maximum random words constant
    const maxRandomWords = await api.consts.randomness.maxRandomWords;

    console.log('Maximum Random Words:', maxRandomWords.toString(), 'words');

    process.exit(0);
  } catch (error) {
    console.error('Error querying max random words:', error);
    process.exit(1);
  }
};

// Execute the script
main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});
minBlockDelay() - the minimum number of blocks (after the block in which the request was made) that must pass before a local VRF request can be fulfilled

None

u32 - the minimum number of blocks (after the block in which the request was made) that must pass before a local VRF request can be fulfilled

import { ApiPromise, WsProvider } from '@polkadot/api';

const main = async () => {
  // Initialize the API
  const api = await ApiPromise.create({
    provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
  });

  try {
    // Get the minimum block delay constant
    const minBlockDelay = await api.consts.randomness.minBlockDelay;

    console.log('Minimum Block Delay:', minBlockDelay.toString(), 'blocks');

    process.exit(0);
  } catch (error) {
    console.error('Error querying min block delay:', error);
    process.exit(1);
  }
};

// Execute the script
main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});
Last update: November 22, 2024
| Created: August 12, 2022