Home >Technology peripherals >It Industry >Solidity Pitfalls: Random Number Generation for Ethereum
This article is sponsored and created by iOlite. Thank you for supporting the partners who made SitePoint possible.
Solidity is a relatively new language that contains issues related to the code and its intended use because there is no perfect code. This article will guide you best practices and pitfalls when using random numbers as input to Ethereum smart contracts.
Key Points
block.timestamp
and block.difficulty
, miners can manipulate these values. Solidity Random Number Generation
Solidity Unable to create random numbers. In fact, all algorithms that create random numbers are pseudo-random—no language can create completely random numbers. The problem with Solidity is that complex algorithms are too expensive and therefore a more basic solution is used. Apart from that, the Solidity code should be deterministic, as it will run on multiple nodes. We need an algorithm that can generate a random number at once and use it on multiple nodes. Information such as clock time is not available to generate random numbers, so we have to look for other options. As a developer, you should be aware of this problem because an attacker is able to predict results in certain situations.
One of the most commonly used algorithms is the "Linear Congruence Generator" (LCG). It is one of the oldest algorithms, fast and easy to understand. LCGs are a good choice for embedded systems because they only have limited memory. However, it does not work with password security applications. Nevertheless, it is still used in smart contracts, as fast algorithms are cheaper in terms of gas costs.
The algorithm itself performs the following steps:
Let's explore different ways to create random numbers using the lottery smart contract example. Users can join the lottery by sending 0.1 Ether to the contract and an integer between 0 and 250.
block.timestamp
& block.difficulty
Whenever the miner confirms a transaction, a block.timestamp
is assigned. No player on our lottery contract can control it. Let's take a look at this code used to create random numbers.
<code class="language-solidity">function random() private view returns (uint8) { return uint8(uint256(keccak256(block.timestamp, block.difficulty))%251); }</code>
Find Gist here.
This code first hash the block timestamp and difficulty. Next, we convert the hash value to an integer and divide it by 251 to get an integer between 0 and 250. However, the problem with this code is that we should not trust miners to choose the winner.
We need more arbitrary data to select our winner. We can use the address of the players who have entered our lottery smart contract, but we have to hide it because they may abuse it. Since all information is recorded on the blockchain, this information cannot be hidden.
The numbers that can be submitted to our lottery smart contract. Users must have the hashing number they selected with their Ethereum address. This gives us a pretty random number.
With that being said, randomness is possible, but you just need to use an oracle to get the random number from outside the blockchain. The problem with using external data is that it is very difficult to prove that the number is actually random and to ensure that the off-chain entity does not manipulate the random number in any way. This is where Chainlink VRF comes into play. Chainlink VRF (Verified Random Function) is how we get proven random numbers in Solidity.
Chainlink VRF Adds an event to the blockchain from which the Chainlink node reads the event and returns a random number. On-chain randomness checks are performed through the so-called VRF coordinator. This uses a specific key hash from the oracle and a seed phrase from the user, as well as some cryptography to ensure that the number is a true random number. In this way, we can get an unbiased random number.
Developers need to consider when to choose a winner. Information such as clock time is not available in the Ethereum virtual machine, because the code will run at different times on multiple nodes. This makes it more difficult to choose the winner. One way is to implement a function in your smart contract that will turn off the lottery and select the winner. This is not as decentralized as we would have hoped. The owner of the contract can close the lottery when it is determined that their friend will win. We must avoid this kind of cheating.
A better option is to use the Ethereum alarm clock. It is a service that allows scheduling transactions to be executed later on the Ethereum blockchain. This service is completely trustless, which means the entire service runs as a smart contract. Basically, the Ethereum alarm uses block numbers to schedule transactions. Note that this does not mean that the contract will start on its own. It relies on the user's interest in calling the "Select Winner" function (Ether reward). Of course, if no one calls your function, your lottery will fail.
Random.org provides an API that provides a random data source through JSON. Ethereum smart contracts can use this data source to feed algorithms for selecting random numbers. Because security is important, digital signatures can be used. Random data will be signed by Random.org. You can verify the integrity of the data so you can prove that it is indeed from Random.org and that the data has not been tampered with.
RANDAO is a new project in the blockchain field, focusing entirely on providing random numbers. They use a combination of oracles and smart contracts to give you random numbers. However, RANDAO services are currently very slow. If you have an app that you use frequently, this is not ideal.
You can also use a monitor in your code that checks the block number until it matches the target number you set.
<code class="language-solidity">function random() private view returns (uint8) { return uint8(uint256(keccak256(block.timestamp, block.difficulty))%251); }</code>
Source. Gist.
iOlite is creating a product that accepts natural language to create smart contracts. It uses the Stanford Natural Language Processing (NLP) engine, called the Fast Adaptation Engine (FAE). iOlite relies on Solidity experts for community training. A Solidity expert (contributor) can define a structure containing one or more sentences and append it to the corresponding smart contract code.
The Stanford NLP engine is designed to understand complex languages. The complexity of the language depends on the amount of machine training. After proper training, the engine will be able to create complex smart contracts. FAE is able to create such contracts because complex contracts are not actually that complicated. Experts can split the request into multiple smaller snippets of code and append it to a sentence.
When someone enters multiple sentences, it will look for the corresponding structure/sentence to build a "complex" contract. Contributors will receive iOlite token rewards through the mining process of the new structure.
The advantage of using iOlite is that smart contract experts can solve problems such as random number generation for you. You can find more information at iOlite.io.
Conclusion
As you can see, generating true random input is not easy. Don't rely on block.timestamp
, now
and block.blockhash
as sources of randomness. A good solution includes combining several pseudo-random data inputs and using oracles or smart contracts to make it more reliable. You need to be 100% sure no one can tamper with the data entered into the smart contract.
Please be careful and think twice before implementing random number generation logic.
FAQ for Random Number Generation in Solidity (FAQ)
Solidity (the programming language used to write Ethereum smart contracts) does not have built-in functions to generate random numbers. This is because blockchain (the basic technology of Ethereum) is essentially deterministic. This means that given a set of inputs, the output will always be the same. This certainty is crucial to maintaining the integrity and security of the blockchain. However, it makes generating true random numbers a challenge, because the concept of randomness is inherently nondeterministic.
Developers use several methods to generate pseudo-random numbers in Solidity. A common method is to use the keccak256 hash function, whose input is difficult to predict, such as the current block timestamp and block difficulty. Another approach is to use an oracle service that provides random numbers from off-chain sources. However, each approach has its own limitations and potential security risks.
Although the keccak256 hash function can be used to generate pseudo-random numbers, it poses some potential security risks. Since inputs to hash functions such as current block timestamps and block difficulty are publicly available on the blockchain, malicious miners may manipulate these values to affect the output generated by random numbers.
Original Services can provide random numbers from off-chain sources. These services act as a bridge between the blockchain and the outside world, allowing smart contracts to interact with data that is not available to the blockchain itself. However, using oracle services introduces a level of trust, because smart contracts must rely on oracles to provide accurate and unbiased random numbers.
Commitment-Revealing scheme is a way to generate random numbers in a decentralized and secure way. In the Commitment-Revealing Scheme, participants first commit a secret number, and then all secret numbers are revealed at the same time, and a random number is generated based on these secrets. This approach prevents any single participant from being able to influence the output generated by random numbers.
Real random numbers are crucial for many types of smart contracts, such as those used for games of chance, lottery, and other applications that require randomness. If the random numbers used in these contracts can be predicted or affected, it can lead to unfair results and even allow malicious actors to exploit the contract.
The blockhash function in Solidity can be used to generate pseudo-random numbers. This function returns the hash value of the given block number, which is unpredictable and varies with each block. However, this method has its limitations. For example, the blockhash function only works on the most recent 256 blocks, and the blockhash of future blocks cannot be known before mining.
There is a major limitation to using the current block timestamp as input to generate random numbers. Miners have some influence on the timestamps of blocks they mine, meaning they may manipulate the timestamps to affect the output generated by random numbers.
RANDAO (Random Number DAO) beacon is a decentralized and transparent way to generate random numbers. Participants in the RANDAO beacon promise secret numbers, which are then revealed and combined to generate a random number. This approach is designed to prevent any single participant from being able to influence the output generated by random numbers.
Research and proposals on improving random number generation in Solidity and other blockchain platforms are underway. For example, Ethereum 2.0 (an upcoming upgrade to the Ethereum network) is expected to include a built-in random number generator. However, before these improvements are implemented, developers must continue to use existing approaches and their inherent limitations and potential security risks.
The above is the detailed content of Solidity Pitfalls: Random Number Generation for Ethereum. For more information, please follow other related articles on the PHP Chinese website!