前言:
DApp前些日子比較火, 這段時間有些低迷. 我也是後知後覺, 如今才接觸一些, 這篇博文就當作DApp的初次印象吧.
本文要寫的是基於智能合約的博彩遊戲DApp—骰子游戲, 來看看它是怎麼實現的, 以及它背後的一些考量.算法
遊戲介紹:
骰子游戲比較簡單, 就是選擇0~99之間一個數N, 而後擲骰子, 若小於該數N, 則勝, 並相應的賠率, 若大於等於則輸.後端
數字N在[1, 99]的範圍內 P(勝率) = N / 100; O(賠率) = 1 / P(勝率) = 100 / N;
好比選擇N=1, 則只有系統出0才能贏, 則勝率P爲1%, 賠率爲100x.
能夠參考stake, 不熟悉該遊戲規則的人, 能夠體驗一下該遊戲.
骰子游戲這個遊戲堪稱幣圈的傳奇, 它極致簡單卻創造了暴富神話.dom
智能合約:
DApp本質是去中心化的App, 它但願去掉中心化的後端服務, 取而代之的運行於區塊鏈虛擬機上的服務. 而這個服務就是由智能合約所定義和描述的, 它是公開和透明的.函數
pragma solidity ^0.4.0; contract MyDice { // 合約建立者 address private owner; modifier onlyOwner() { require(msg.sender == owner); _; } constructor() public { owner = msg.sender; } // 房主給合約錢包裏充錢 function recharge() onlyOwner payable public { } // 房主主動從合約錢包中提現 function withdraw(uint32 _amount) onlyOwner public { owner.transfer(_amount); } // solidity不能返回結構, 但能夠返回元組 // @param _num 爲選擇的數字 [1, 99]之間 // @return (玩家選擇數字, 籌碼, 生成的數字, 賠付籌碼) function play(uint8 _num) payable public returns (uint8, uint256, uint8, uint256) { require(_num >= 1 && _num <= 99); // 生成[0, 99]的隨機數 uint8 tval = randomInt(0, 99); if ( tval < _num ) { // 計算賠付的值 uint256 payout = uint256(msg.value * 100 / _num); msg.sender.transfer(payout); return (_num, msg.value, tval, payout); } else { return (_num, msg.value, tval, 0); } } // 生成[min, max]之間的一個隨機數 function randomInt(uint8 min, uint8 max) private view returns(uint8) { require(max > min); bytes32 hash = keccak256( abi.encodePacked(now, msg.sender, block.difficulty) ); return uint8(uint256(hash) % (max - min + 1)) + min; } }
合約即代碼, 玩家不再用懼怕被傳統中心化的遊戲服務做弊坑錢, 由於代碼邏輯清清楚楚. 區塊鏈
缺陷:
這其實也是通病, 就是智能合約對隨機算法支持比較弱, 純粹是一些加密函數+隨機變量種子來實現, 好比區塊鏈block的信息, 時間戳, 以及調用方信息. 而公鏈上數據是公開的, 黑客可經過控制這些隨機變量, 從而來預測結果, 這樣就大大破壞遊戲自己的公平性.
所以通常不建議, 合約現有機制來實現隨機數的產生, 而是藉助第三方(Oraclize)來實現. ui
總結:
關於合約對隨機算法不友好的問題, 有不少服務採用混合模型, 好比Dice2win 就採用的hash-commit-reveal機制, 很是完美地解決該類問題, 有空咱們再聊聊.加密