How to Generate Random Numbers on Ethereum Using VRF

How Chainlink Solved Ethereum’s “Random Problem”

Random numbers and Blockchains have always been in disagreement. Until now, a verifiably random function has never existed on the Blockchain

The problem stems from the fact that when transactions are mined, they need to be confirmed by more than one node on the network. This means that every node must come to the same conclusion. So, if a function was truly random, each node would come to a different conclusion, resulting in an unconfirmed transaction.

There have been workarounds that result in a pseudo-random generation, but until now all known methods have been either not truly random, or vulnerable to manipulation.

Introducing Chainlink

“The Chainlink network provides reliable tamper-proof inputs and outputs for complex smart contracts on any blockchain.” — chain.link

Blockchains and smart contracts are great at performing computation according to a set of immutable rules. The problem is that the rules can only be applied to data inside the system. Getting verifiable data from outside the system is difficult.

Chainlink’s mission is to solve this by providing decentralised oracles, enabling the Blockchain to access data outside of its ecosystem. Oracles are essentially a bridge between the Blockchain and the outside world.

That’s so random

In a recent article, Chainlink announced the release of their new Verifiable Random Function (VRF). The function, now available for developers to integrate into their DApps on several testnets, enables smart contracts to retrieve random numbers which are verifiable on-chain. This means no more vulnerabilities and guaranteed randomness.


How it works

If you want to generate a random number in Javascript, the code is pretty simple:

Math.random();

In a single execution of one line, you retrieve a random number. This is not how VRF works. Unlike Javascript, VRF works over a few transactions.

Here’s the sequence of events:

  1. Your smart contract requests a random number from VRF, via transaction.
  2. VRF generates that number and verifies it.
  3. VRF prepares the response.
  4. VRF then sends the number back to your contract, via another transaction.

For point 4 to succeed, your contract needs to implement a known function so that VRF can call back with the result. But how can this be implemented in your project?

How to implement randomness

Let’s create a new smart contract called RandomGenerator, this is where we’ll make the call to VRF and receive the result.

Step 1: Create the consumer contract

We’re going to use a contract provided by Chainlink called VRFConsumerBase, which is an abstract contract that defines the minimum functions we need to consume VRF. Let’s define the beginnings of our “RandomGenerator.sol” file like this:

pragma solidity ^0.6.2;

import "https://raw.githubusercontent.com/smartcontractkit/chainlink/develop/evm-contracts/src/v0.6/VRFConsumerBase.sol";

contract RandomGenerator is VRFConsumerBase {

    constructor(address _vrfCoordinator, address _link) VRFConsumerBase(_vrfCoordinator, _link) public {
    }

}

VRFConsumerBase is still in late testing, so it’s not yet available in production packages. This is why we are using an HTTP URL from Github for the import.

The base contract takes two parameters representing the coordinator and the address of the LINK ERC20 token. These are fixed addresses on each network (more on this later). 

Step 2: Overriding functions

VRFConsumerBase comes with two functions vital to the VRF process. 

The first is called requestRandomness which is already implemented, and which we don’t need to override. This is the function that makes the initial call to VRF.

The next is called fulfillRandomness, and this is the function which VRF calls back to when it has generated the number. We can override this to perform actions on the random number when it gets called. 

Our contract is simply going to store the generated random number in a state variable, called randomNumber, so that we can query it when it’s finished. It should look something like this:

pragma solidity ^0.6.2;

import "https://raw.githubusercontent.com/smartcontractkit/chainlink/develop/evm-contracts/src/v0.6/VRFConsumerBase.sol";

contract RandomGenerator is VRFConsumerBase {
    
    bytes32 public reqId;
    uint256 public randomNumber;

    constructor(address _vrfCoordinator, address _link) VRFConsumerBase(_vrfCoordinator, _link) public {
    }
    
    function fulfillRandomness(bytes32 requestId, uint256 randomness) external override {
        reqId = requestId;
        randomNumber = randomness;
    }
}

We’ve added the override for the fulfillRandomness function, and set the state variables reqId and randomNumber to equal the values that the function receives.

Step 3: Generating the number

As I mentioned earlier in step 1, there are a few addresses and other values expected by the function calls that need to be passed in as parameters. 

When deploying the contract and calling the constructor, it needs the VRF coordinator address and the address of the LINK token on the network. On the Ropsten testnet these are:

  • VRF coordinator: 0xf720CF1B963e0e7bE9F58fd471EFa67e7bF00cfb
  • LINK address: 0x20fE562d797A42Dcb3399062AE9546cd06f63280

When calling the requestRandomness function, we need to pass in the key hash by which randomness is generated, the fee for the random generation (in LINK tokens) and the seed to generate the randomness against (this last one is provided by us). The function signature looks like this:

function requestRandomness(bytes32 _keyHash, uint256 _fee, uint256 _seed) public returns (bytes32 requestId)

On Ropsten, the parameter values are:

  • Key hash: 0xced103054e349b8dfb51352f0f8fa9b5d20dde3d06f9f43cb2b85bc64b238205
  • Fee (1 LINK): 1000000000000000000
  • Seed: [whatever_you_want_your_seed_to_be]

So our call would look something like this:

// set ropsten key hash
bytes32 keyHash = "0xced103054e349b8dfb51352f0f8fa9b5d20dde3d06f9f43cb2b85bc64b238205";
// set ropsten LINK fee
fee = 1000000000000000000;
// set example seed
seed = 123456789;
// make call to request randomness
bytes32 reqId = rand.requestRandomness(keyHash, fee, seed);

When the result comes back, the value will be present and can be retrieved by calling:

rand.randomNumber;

Try it out yourself

This section is going to walk through how we can get a random number from VRF using Remix IDE and Metamask. Make sure you have Metamask extension installed on your browser before continuing.

  • Head over to Remix IDE.
  • If you’ve not used Remix before, make sure you’re using Solidity, as shown in figure 3.
Figure 3
Figure 3
  • Create a new file called RandomGenerator and paste in the code from figure 2.
  • Using the left menu, click on the Solidity icon and chose 0.6.2 compiler version, as shown in figure 4.
Figure 4
Figure 4
  • Then, click on the button just below that and chose “Injected web3” in the dropdown, as shown in figure 5.
Figure 5
Figure 5
  • This should prompt a connection request from Metamask which you should accept.
  • Make sure you’re using the Ropsten testnet on Metamask, as shown in figure 6.
Figure 6
Figure 6
  • Make sure you have some Ropsten Ether in your Metamask account, which you can request here.
  • Heading back to Remix, on that same tab, you should see an orange “Deploy” button, click that button and accept the contract deployment request from Metamask.
  • Once deployed, we need to make sure the contract has LINK tokens so it can request random numbers. Head over the Ropsten LINK faucet and paste in your Metamask address, so that you receive 100 LINK in Metamask.
  • Metamask won’t know where the LINK token is on Ropsten, so we need to add it. In Metamask, to the left of your account name, click the burger symbol, then click “Add Token” at the bottom. 
  • Under “Custom Token”, add the address: 0x20fE562d797A42Dcb3399062AE9546cd06f63280. The rest of the details should fill in automatically. When submitted, providing you requested LINK to the correct address, you should see 100 LINK in your account. Figure 7 shows an account with 70 LINK.
Figure 7
Figure 7
  • Back to Remix, copy the address of the deployed contract by clicking the button circled in figure 8.
Figure 8
Figure 8
  • Now we’re going to send the contract some of our LINK. Head back onto Metamask, and click on the 3 dots next to the 100 LINK. Paste the contract address and send 10 LINK. Once the transaction has been confirmed, move to the next step.
  • In Remix, we can now request randomness. In the same tab, scrolling down you’ll find more orange buttons representing public functions, as shown in figure 9. Click on the arrow to the right of requestRandomness to expand the parameters.
Figure 9
Figure 9
  • Paste in each of these values into the three input boxes in order: 0xced103054e349b8dfb51352f0f8fa9b5d20dde3d06f9f43cb2b85bc64b238205, 1000000000000000000, 123456789(or whatever you want your seed to be). Then hit “Transact”!
Figure 10
Figure 10

This may take some time, so you should keep an eye on the transaction in Etherscan that the output terminal gives you.

Figure 11: Etherscan transaction address
Figure 11: Etherscan transaction address

Once that transaction has completed, we need to wait for VRF to generate the random number and send it back to our contract. After a few minutes, check if your contract has received the random number by clicking the blue “randomNumber” button below the orange button where we sent our transaction in Remix, as shown in figure 12.

Figure 12: Receiving the random number
Figure 12: Receiving the random number

If all goes well, you should have a random number like me, which is 30207470459964961279215818016791723193587102244018403859363363849439350753829

Congratulations!

Conclusion

Chainlink has demonstrated that verifiable random numbers are now possible in smart contracts. We’ve explained how the mechanism works, how to integrate the code into smart contracts, and a demonstration of retrieving random numbers using the Remix IDE.


Further Reading

If you’re interested in Blockchain Development, I write tutorials, walkthroughs, hints, and tips on how to get started and build a portfolio. Check out some of these resources:

Blockchain Development Resources To Follow Right Now

Newsletter

Get Best Crypto Deals