如何讓 _generateRandomDna 函數(shù)返回一個(gè)全(半) 隨機(jī)的 uint?
Ethereum 內(nèi)部有一個(gè)散列函數(shù)keccak256,它用了SHA3版本膀跌。一個(gè)散列函數(shù)基本上就是把一個(gè)字符串轉(zhuǎn)換為一個(gè)256位的16進(jìn)制數(shù)字。字符串的一個(gè)微小變化會(huì)引起散列數(shù)據(jù)極大變化。
這在 Ethereum 中有很多應(yīng)用,但是現(xiàn)在我們只是用它造一個(gè)偽隨機(jī)數(shù)齐蔽。
例子:
//6e91ec6b618bb462a4a6ee5aa2cb0e9cf30f7a052bb467b0ba58b8748c00d2e5
keccak256("aaaab");
//b1f078126895a1424524de5321b339ab00408010b7cf0e6ed451514981e58aa9
keccak256("aaaac");
58aa9
keccak256("aaaac");
顯而易見(jiàn),輸入字符串只改變了一個(gè)字母床估,輸出就已經(jīng)天壤之別了含滴。
注: 在區(qū)塊鏈中安全地產(chǎn)生一個(gè)隨機(jī)數(shù)是一個(gè)很難的問(wèn)題, 本例的方法不安全丐巫,但是在我們的Zombie DNA算法里不是那么重要谈况,已經(jīng)很好地滿足我們的需要了。
類(lèi)型轉(zhuǎn)換
有時(shí)你需要變換數(shù)據(jù)類(lèi)型鞋吉。例如:
uint8 a = 5;
uint b = 6;
// 將會(huì)拋出錯(cuò)誤鸦做,因?yàn)?a * b 返回 uint, 而不是 uint8:
uint8 c = a * b;
// 我們需要將 b 轉(zhuǎn)換為 uint8:
uint8 c = a * uint8(b);
上面, a * b 返回類(lèi)型是 uint, 但是當(dāng)我們嘗試用 uint8 類(lèi)型接收時(shí), 就會(huì)造成潛在的錯(cuò)誤励烦。如果把它的數(shù)據(jù)類(lèi)型轉(zhuǎn)換為 uint8, 就可以了谓着,編譯器也不會(huì)出錯(cuò)。
實(shí)戰(zhàn)演習(xí)
給 _generateRandomDna 函數(shù)添加代碼! 它應(yīng)該完成如下功能:
第一行代碼取 _str 的 keccak256 散列值生成一個(gè)偽隨機(jī)十六進(jìn)制數(shù)坛掠,類(lèi)型轉(zhuǎn)換為 uint, 最后保存在類(lèi)型為 uint 名為 rand 的變量中赊锚。
我們只想讓我們的DNA的長(zhǎng)度為16位 (還記得 dnaModulus?)。所以第二行代碼應(yīng)該 return 上面計(jì)算的數(shù)值對(duì) dnaModulus 求余數(shù)(%)屉栓。
pragma solidity ^0.4.19;
contract ZombieFactory {
uint dnaDigits = 16;
uint dnaModulus = 10 ** dnaDigits;
struct Zombie {
string name;
uint dna;
}
Zombie[] public zombies;
function _createZombie(string _name, uint _dna) private {
zombies.push(Zombie(_name, _dna));
}
function _generateRandomDna(string _str) private view returns (uint) {
uint rand = uint(keccak256(_str));
return rand % dnaModulus;
}
// 從這里開(kāi)始
}