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 randomIn 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 worksIf 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:
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 randomnessLet’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 contractWe’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 functionsVRFConsumerBase 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 numberAs 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:
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:
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 yourselfThis 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.
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 addressOnce 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 numberIf all goes well, you should have a random number like me, which is 30207470459964961279215818016791723193587102244018403859363363849439350753829.
Congratulations!
ConclusionChainlink 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 ReadingIf 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:
All Rights Reserved. Copyright , Central Coast Communications, Inc.