[ad_1]
This is a widespread practice to introduce randomness into smart contracts using block hashes. Plenty of popular smart contracts are based on this idea despite its serious consequences. In this text, we will highlight a number of pitfalls of such an approach.
Randomness in smart contracts is usually used for some kind of lotteries. Let’s pretend that in our case we allow users to mint NFT with features that are a result of randomness. Like in Developers Dao you may mint a developer character that either codes in Java or Go.
Why there is no random implemented into solidity?
In most programming languages you can use a function to generate a random number (usually based on a system clock). In the blockchain, however, the same code is intended to be run on multiple independent nodes (fancy name for computers), and the output of computations is compared at the consensus state. If there will be a truly random factor in those calculations there will hardly be any consensus ever as all random dependent results will differ from node to node. Consensus can only occur when all (most) nodes return the same results.
Developers have to handle randomness somehow. Often using some totally deterministic algorithms that are in no way random but provide a better or worse illusion of uncertainty.
Randomness by obscurity
A good example would be performing a couple of math operations on given non-random numbers that are hard to understand for humans. This is the case for a great community DAO The Developer Dao where everyone could have claimed a developer’s avatar each with some specific features i.e. OS. On claiming you give the avatar id and it is dynamically created from the id and the random kicks in.
function random(string memory input) internal pure returns (uint256) {
return uint256(keccak256(abi.encodePacked(input)));
}function getOS(uint256 tokenId) public view returns (string memory) {
return pluck(tokenId, "OS", osses);
}
//....
function pluck(uint256 tokenId, string memory keyPrefix, string[] memory sourceArray) internal pure returns (string memory) {
uint256 rand = random(string(abi.encodePacked(keyPrefix, toString(tokenId))));
string memory output = sourceArray[rand % sourceArray.length];
return output;
}
As you can see in the code snippet above (full code available here etherscan.io) the whole randomness here is just making calculations on the number provided by a user. This is probably just to forbid picking developer avatars they like, instead, of making it a fun game of even chances for features one may want.
Randomness based on block hash
This is usually a mix of math computations and the block number. Since it seems hard to foresee the block number in which the tx will be realized this is a common (and unfortunately naive) approach.
The frequent misconception about randomness by block hash is that only miners are a threat.
Example 1:
Developers may treat this risk as neglectable thinking that miners have more at stake than the benefit from manipulating transaction orders. Miners would need to manipulate transactions order in such a way that they let their specific transaction enter a certain block that guarantees beneficial results.
Why is “random” based on block hash vulnerable?
Firstly because it is not random at all, and is so for a couple of reasons.
- Increasing odds (easy & ineffective)
You cannot foresee but you can increase your odds. By analyzing the delay between your intention and the block the transaction finally enters you may notice it takes i.e. between 2–5 blocks and thus you may easily try to enter the right block paying a lot for gas (to be the first to enter the block and not be postponed until next one) or even putting a series of transaction in order with increasing nonces.
2. Using another smart contract (complex & effective)
This approach relies on the fact that you may call a function from a smart contract to invoke a function on a lottery smart contract (the one with random). This approach allows us to make sure what the current block is and make a decision whether we take part in the lottery or not. If our function is called in a specific block we are sure that the function on the lottery smart contract will be called in the same one. Additionally if taking part in the lottery costs a fee we can not pay until we are 100% sure that we will be “lucky”.
The second approach is hard to mitigate. You may protect the smart contract from being used by other smart contracts however this will also disable specific wallets like i.e multi-sig wallets (which are in fact smart contracts) from interacting with the smart contract.
Is there any way to improve randomness in smart contracts?
- Decentralized oracle i.e. chainlink VRF. This approach is pretty complex and requires much more implementation than any block hash-based solution plus it costs gas and makes the whole experience even more async which again might require additional implementation of UI/UX.
- Commit and reveal of results — there is a certain number of slots provided with hidden content. At some point in time users pick their slots and the content is revealed by the owner later on. This experience is worse as one needs to wait for the publication of the results. It may also decrease users’ engagement in case buying the next slot is possible.
Summary
There is no ideal solution to generating random numbers in the blockchain world. Developers are more and more frequently utilizing the benefits of decentralized oracles for this purpose. This seems to be the right choice as long as you can trust that the oracle itself will not manipulate the results. And this is against the idea of a trustless blockchain.
New to trading? Try crypto trading bots or copy trading on best crypto exchanges
[ad_2]
Source link