场景
在合约中某些时候需要生成不可重复的随机数,比如NFT的TokenId由已开始的自增序列改为散列随机出现在可允许的范围内。就像开盲盒一样,可以随机开出。同时以太坊的随机数安全性是未知的,因为生成随机数的所有数值在生成之前都是可见的。如果需要生成真随机数可以使用”预言机“。
代码
contract TestHash{
//散列随机数的范围,此处为6,表明最终的随机数范围 [1,6]
uint constant public TOKEN_LIMIT = 6;
//散列数组,用于解决随机时出现重复数值的情况
uint[TOKEN_LIMIT] public indices;
//该方法被调用了多少次,等于已经产生的随机数数量。
uint nonce;
function randomIndex() public returns (uint) {
uint totalSize = TOKEN_LIMIT - nonce;
uint index = uint(keccak256(abi.encodePacked(nonce, msg.sender, block.difficulty, block.timestamp))) % totalSize;
uint value = 0;
if (indices[index] != 0) {
value = indices[index];
} else {
value = index;
}
// Move last value to selected position
if (indices[totalSize - 1] == 0) {
// Array position not initialized, so use position
indices[index] = totalSize - 1;
} else {
// Array position holds a value so use that
indices[index] = indices[totalSize - 1];
}
nonce++;
// Don't allow a zero index, start counting at 1
return value+1;
}
}
解释
这段代码的逻辑,仔细思考一下其实不难的。 index是产生随机数,具体做法是将一段bytes进行sha256哈希。然后得到一个uint256长整型对上确界取模。上确界就是总数减去已产生的次数比如总数是6个如果调用这个方法已经产生了2个随机数那么此时的上确界就是4。这段代码解决多次随机到同一个数(上面提到每次调用产生不不重复的数)的方式是,如果随机数相同则把当前的上确界返回,同时把下一个上确界赋值给当前indices数组随机数索引的位置,等待下一次调用。
这段代码的源码来源于 Meebits 的主网合约。