Random Number Generation Using Chainlink

Tusharmahajan
Simform Engineering
7 min readJun 9, 2023

Demystifying Random Number Generation in Smart Contracts: A Practical Tutorial with Chainlink VRF

Note: In the context of blockchain technology, an oracle is a service or mechanism that provides external data to smart contracts. Oracles act as bridges between blockchain-based smart contracts (which operate on a decentralized network) and the real world (where data and events occur outside of the blockchain).

Introduction

Blockchain technology has revolutionized industries with its decentralized and transparent nature. However, one challenge it faces is obtaining reliable and verifiable external data. Chainlink, a decentralized oracle network, bridges this gap by providing smart contracts with real-world data. In this blog, we will explore the concept of Chainlink oracles and their role in enhancing blockchain security and fairness, with a focus on random number generation using Chainlink.

Understanding Chainlink Oracles

Chainlink oracles act as intermediaries between smart contracts and external data sources, ensuring the accuracy and integrity of the data. They retrieve real-time information from various sources, such as APIs, web services, and IoT devices, and deliver it to smart contracts securely. The decentralized nature of Chainlink oracles eliminates single points of failure and enhances reliability and transparency.

Importance of Random Number Generation

Random number generation is crucial for various applications, including gambling, gaming, and cryptographic protocols. In blockchain-based systems, ensuring the fairness and unpredictability of random numbers is essential for maintaining trust and avoiding manipulation. Traditional random number generation within the blockchain presents challenges, but Chainlink provides a reliable solution.

Random Number Generation with Chainlink

Chainlink’s VRF (Verifiable Random Function) is a key component for generating random numbers on the blockchain. It combines cryptographic techniques to produce random numbers that are tamper-proof and verifiable. The process involves multiple independent oracles retrieving random data, hashing it, and then collectively generating a random number. This approach ensures fairness, transparency, and resistance to manipulation.

Create Subscription

To create Subscription, click here.

On clicking Create Subscription, you will see the following page:

Fill in the details here. Verify your account address. You can skip putting in your email address and project name, as these fields are optional. Then, click on Create Subscription, and sign the transaction from metamask. Wait till you see the transaction confirmation.

Your Subscription is now created! Add some funds (LINK Token) into this newly created subscription. Click on ‘Add funds’ to do that.

If you don’t have any LINK Tokens in your Sepolia account, you can get them from faucets.chain.link. Make sure to acquire the necessary LINK Tokens before proceeding.

After the successful creation of your Subscription, you will receive a unique Subscription ID. Keep this ID handy, as you will need it during the deployment of your smart contract.

Let's get started with random number generation

To begin, we’ll create a Hardhat project. If you’re new to Hardhat and unsure how to write and deploy smart contracts, you can refer to the blog post provided below:

Inside the contract folder of your Hardhat project, create a new file named RandomNumberConsumerV2.sol Copy and paste the contract code snippet provided below into this file.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;

import "@chainlink/contracts/src/v0.8/interfaces/VRFCoordinatorV2Interface.sol";
import "@chainlink/contracts/src/v0.8/VRFConsumerBaseV2.sol";


contract RandomNumberConsumerV2 is VRFConsumerBaseV2 {

event ReturnedRandomness(uint256[] randomWords);
event RequestSent(uint256 requestId, uint32 numWords);
event RequestFulfilled(uint256 requestId, uint256 randomWord);

struct RequestStatus {
bool fulfilled; // whether the request has been successfully fulfilled
bool exists; // whether a requestId exists
uint256 randomWord;
}
mapping(uint256 => RequestStatus)
public s_requests; /* requestId --> requestStatus */

VRFCoordinatorV2Interface immutable COORDINATOR;

uint64 immutable s_subscriptionId;

bytes32 immutable s_keyHash;

uint32 constant CALLBACK_GAS_LIMIT = 100000;

uint16 constant REQUEST_CONFIRMATIONS = 3;

uint32 constant NUM_WORDS = 1;

uint256[] public s_randomWords;

uint256 public requestId;
address s_owner;
uint256[] public requestIds;
uint256 public lastRequestId;



constructor(
uint64 subscriptionId,
address vrfCoordinator,
bytes32 keyHash
) VRFConsumerBaseV2(vrfCoordinator) {
COORDINATOR = VRFCoordinatorV2Interface(vrfCoordinator);
s_keyHash = keyHash;
s_owner = msg.sender;
s_subscriptionId = subscriptionId;
}

function requestRandomWords() external returns(uint256) {
requestId = COORDINATOR.requestRandomWords(
s_keyHash,
s_subscriptionId,
REQUEST_CONFIRMATIONS,
CALLBACK_GAS_LIMIT,
NUM_WORDS
);

s_requests[requestId] = RequestStatus({
randomWord:0,
exists: true,
fulfilled: false
});
requestIds.push(requestId);
lastRequestId = requestId;
emit RequestSent(requestId, NUM_WORDS);

return requestId;
}

function fulfillRandomWords(uint256 requestId, uint256[] memory randomWords)
internal
override
{
require(s_requests[requestId].exists, "request not found");
s_requests[requestId].fulfilled = true;
uint256 randomNumber=randomWords[0];
s_requests[requestId].randomWord = randomNumber;
emit RequestFulfilled(requestId,randomNumber);
}

function getRequestStatus(
uint256 _requestId
) external view returns (bool fulfilled, uint256 randomWord) {
require(s_requests[_requestId].exists, "request not found");
RequestStatus memory request = s_requests[_requestId];
return (request.fulfilled, request.randomWord);
}

}
  1. This contract uses the Chainlink VRF system to generate random numbers on the Ethereum blockchain.
  2. It imports the necessary contracts from the Chainlink project to interact with the VRF system.
  3. The contract defines events to emit when random numbers are returned, requests are sent, and requests are fulfilled.
  4. It defines a struct called RequestStatus to store the status of each random number request.
  5. The contract maintains a mapping that links each request ID to its corresponding RequestStatus.
  6. It initializes the VRF coordinator address, Subscription ID, and key hash in the constructor.
  7. The requestRandomWords function sends a request to the VRF coordinator to generate random numbers, updates the request status accordingly, and, thus, triggers the random number generation process.
  8. When the VRF coordinator fulfills a request, the fulfillRandomWords function is called internally to update the request status and store the generated random number.
  9. There is a function called getRequestStatus to retrieve the status and generated random number of a specific request.
  10. The contract keeps track of the most recent request ID, the contract owner’s address, and all request IDs made by the contract.
  11. Overall, this contract enables users to request random numbers and provides a convenient way to check the status and generated random number for each request.

To deploy the contract, follow these steps:

  1. Create a new file named deploy.js in the script folder.
  2. Copy and paste the code snippet provided below into the deploy.js file
const hre = require('hardhat');

async function main() {
//on sepolia network ,you can change data acouding to your network
//https://docs.chain.link/vrf/v2/direct-funding/supported-networks
//visit thi site for supported network configuration
const subscriptionId ="<Your subscription id>";
const vrfCoordinator = '0x8103B0A8A00be2DDC778e6e7eaa21791Cd364625';
const keyHash =
'0x474e34a077df58807dbe9c96d3c009b23b3c6d0cce433e59bbf5b34f823bc56c';

const RandomNumberConsumerV2 = await hre.ethers.getContractFactory(
'RandomNumberConsumerV2',
);
const random = await RandomNumberConsumerV2.deploy(
subscriptionId,
vrfCoordinator,
keyHash,
);

await random.deployed();

console.log(` deployed to ${random.address}`);
}

main().catch((error) => {
console.error(error);
process.exitCode = 1;
});

3. Replace the subscriptionId in the code with your actual subscription ID.

4. Visit the Chainlink supported network configuration and replace the vrfCoordinator address and keyHash values accordingly.

To deploy the contract on the Sepolia network, run the following command:

npx hardhat deploy — network sepolia

After deploying the contract, you need to add your contract address as a consumer to your Subscription.

Now you can call the contract function requestRandomWords . Wait for the transaction to be confirmed; it will return requestId as a response. Copy that requestId and use it as an input parameter for the functiongetRequestStatus .

If the response shows fulfilled:false, wait for some time and call the function again. Eventually, you will get a response with fulfilled:true, along with a generated random number.

If you wish to review my code, you can refer to my github repository.

Benefits and Use Cases

Chainlink’s random number generation capabilities have far-reaching benefits. It enables fair and unbiased gaming, enhances the security of blockchain-based lotteries, facilitates trustless gambling platforms, and supports cryptographic protocols requiring random inputs. Use cases extend to decentralized finance (DeFi), supply chain management, and more, where verifiable random numbers are essential for secure and trustworthy operations.

Conclusion

Chainlink oracles and random number generation provide crucial building blocks for enhancing security and fairness in blockchain applications. With its decentralized oracle network and VRF capabilities, Chainlink offers a robust solution for obtaining reliable and verifiable external data and generating random numbers. As blockchain technology continues to evolve, Chainlink plays a vital role in expanding the possibilities and use cases across various industries, enabling a more secure and transparent decentralized ecosystem.

To learn more about engineering at Simform, check out the rest of our Engineering Blog, and visit our Simform site. To view and apply to open opportunities, visit our Careers page.

--

--