Understanding Chainlink Verifiable Randomness Function

Understanding Chainlink Verifiable Randomness Function

ยท

5 min read

Chainlink is a decentralized oracle network that connects smart contracts to external data sources, APIs, and payment systems. It was created by Sergey Nazarov and Steve Ellis in 2017 and operates on the Ethereum blockchain.

Chainlink provides a decentralized solution to the Oracle problem by allowing smart contracts to securely and reliably access data and interact with external systems.

Verifiable Randomness Function (VRF)

A blockchain is a predictable, deterministic machine which means the blockchain network behaviour can be accurately predicted and replicated, given the same set of inputs or conditions.
Chainlink VRF provides a verifiable random number generator (RNG) that enables smart contracts to access random values without compromising security or usability. Therefore eliminating the deterministic nature of the blockchain.

There are two means by which smart contracts can get a random number with chainlink VRF, which are:

  • SUBSCRIPTION METHOD

  • DIRECT FUNDING METHOD

For the purpose to make this article short, we will discuss the subscription method alone but you can access the chainlink doc to gain more insight.

SUBSCRIPTION METHOD

Getting a random number from the subscription method can be achieved using the two processes of the subscription method, using either Subscription Manager UI or using Programmatic Subscription.

Subscription Manager UI

Manager UI

To create and fund a subscription we first, go to the Subscription Manager and make sure the network is on Sepolia testnet ETH. Add Link token to the subscription, you can get a Link fauet, note funding your subscription manager with Link Token the amount of Link must be between 2 or above Link.

Add the consumer contract to the Subscription Manager UI. You can find the final code in the Github gist.

Subscription Manager UI

Code Explanation

The COORDINATOR variable is an interface to interact with Chainlink's VRF coordinator from the imported VRFCoordinatorV2Interface.sol contract,s_subscriptionId variable stores the subscription ID for the VRF service and requestIds and lastRequestId stores the IDs for past VRF requests.

keyHash is a unique identifier for the VRF service. callbackGasLimit is the maximum amount of gas that can be used to process a callback request.requestConfirmations sets the number of confirmations required for a VRF request.numWords sets the number of random words to generate for a VRF request.

The two events RequestSent and RequestFulfilled will emit a VRF request when sent and fulfilled respectively. RequestStatus stores the status of a VRF request,s_requests mapping associates a RequestStatus with a request ID.

Constructor provides the subscription id for the contract.

    VRFCoordinatorV2Interface COORDINATOR;

    uint64 public s_subscriptionId;


    uint256[] public requestIds;
    uint256 public lastRequestId;

    bytes32 keyHash = 0x474e34a077df58807dbe9c96d3c009b23b3c6d0cce433e59bbf5b34f823bc56c;

    uint32 callbackGasLimit = 100000;

    uint16 requestConfirmations = 3; 


    uint32 numWords = 2;

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

    struct RequestStatus {
        bool fulfilled; 
        bool exists; 
        uint256[] randomWords;
    }

    mapping(uint256 => RequestStatus) public s_requests; 

    constructor(
        uint64 subscriptionId
    )
        VRFConsumerBaseV2(0x8103B0A8A00be2DDC778e6e7eaa21791Cd364625)
        ConfirmedOwner(msg.sender)
    {
        COORDINATOR = VRFCoordinatorV2Interface(
            0x8103B0A8A00be2DDC778e6e7eaa21791Cd364625
        );
        s_subscriptionId = subscriptionId;
    }

fulfillRandomWords function is an internal function that is called by the VRFConsumerBaseV2 contract when the VRF service returns the requested random numbers. requestRandomWords is an external function that can be called by the owner of the contract to request random numbers from the VRF service. It calls the requestRandomWords function on the COORDINATOR contract and stores the request ID and status in the contract's state. getRequestStatus function can be called by anyone to check the status of a specific request ID. It returns a boolean indicating whether the request has been fulfilled and an array of random numbers if it has been fulfilled.

function fulfillRandomWords(
        uint256 _requestId,
        uint256[] memory _randomWords
    ) internal override {
        require(s_requests[_requestId].exists, "request not found");
        s_requests[_requestId].fulfilled = true;
        // Generate a number from 0 - 20
        for (uint256 i = 0; i < _randomWords.length; i++) {
            _randomWords[i] = _randomWords[i] % uint256(20) + 1;
        }

        s_requests[_requestId].randomWords = _randomWords;
        emit RequestFulfilled(_requestId, _randomWords);
    }

    // Assumes the subscription is funded sufficiently.
    function requestRandomWords()
        external
        onlyOwner
        returns (uint256 requestId)
    {
        // Will revert if subscription is not set and funded.
        requestId = COORDINATOR.requestRandomWords(
            keyHash,
            s_subscriptionId,
            requestConfirmations,
            callbackGasLimit,
            numWords
        );
        s_requests[requestId] = RequestStatus({
            randomWords: new uint256[](0),
            exists: true,
            fulfilled: false
        });
        requestIds.push(requestId);
        lastRequestId = requestId;
        emit RequestSent(requestId, numWords);
        return requestId;
    }

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

Execution of Contract

Using Remix editor to execute the random.sol contract, After deploying the contract check to get the owner and subscription id of the contract.

To request a random number, call the requestRandomWords function that generates the random number from the VRF.

Get the initial call to the requestRandomWords and provide it to the s_requests to check the status of the request.

Two random number 12 and 19 were generated by the VRF coordinator.

Great, you successfully generated a truly randomised number Bravo ๐Ÿฅณ.

Final Thought

In conclusion, the Chainlink Verifiable Randomness Function (VRF) is a powerful tool that provides secure and verifiable randomness to smart contracts on the blockchain. With VRF, developers can create applications with fair and unbiased random outcomes, enabling a wide range of use cases in areas such as gaming, Defi, lotteries, and prediction markets.

If find this article helpful leave a like and follow me on all my socials. Thanks for reading.

Did you find this article valuable?

Support Emmanuel Philip by becoming a sponsor. Any amount is appreciated!

ย