http://www.7klian.com

在以太坊上成立可验证的随机彩票智能合约

41}
 6
34require(state == _state, “Wrong state for this action”);
假如您已经阅读了有关如何利用VRF的文章,那么您将知道生成随机数并不像挪用单个函数那样简朴(譬喻JavaScript中的Math.random())。
第2行确保已付出正确的报名费,第3行确保动静的发件人尚未提交该号码,并将其添加到流程中的条目中。
27}
49entryFee = _entryFee;
47require(_randomNumberGenerator != address(0), “Random number generator must be valid address”);
85uint balance = address(this).balance;
要生成随机数,必需从VRF协调器请求随机性,并实现VRF可以在响应中回调的成果。为此我们需要界说一个VRF利用者(可在此处找到建设VRF利用者的具体信息),在图2中将其称为RandomNumberGenerator。
19LotteryState public state;
26    }
6  payable(owner()).transfer(ownerCut);
69}
10
在我们的界说的第1行中,只能由彩票所有者挪用drawNumber,而且只能在彩票处于打开状态时挪用。
我们的彩票有三个阶段。第一种是开放式,任何人都可以提交新的号码,只需付出少量用度。第二个是封锁的,没有新的数字可以提交,随机数正在生成。第三个已经完成,号码已经生成,赢家已经得到嘉奖。
11_payout(entries[_randomNumber]);
46require(_ownerCut < _entryFee, “Entry fee must be greater than owner cut”);
8}
13}
23uint public winningNumber;
63}
26
4}
2    require(state == _state, “Wrong state for this action”);
1mapping(uint => EnumerableSet.AddressSet) entries;
7  emit NewEntry(msg.sender, _number);
 8if (_randomNumberRequestId == randomNumberRequestId) {
77winningNumber = _randomNumber;
24address randomNumberGenerator;
 5
17mapping(uint => EnumerableSet.AddressSet) entries;
27event LotteryStateChanged(LotteryState newState);
92state = _newState;
37
第1行界说了名称,单个_number参数以及它是public的和payable的事实。它还添加了isState修饰符,以确保彩票是开放的。
利用enum,我们可以界说任意多个阶段。我们称它为LotteryState。在状态变量中,我们界说以下内容:
57require(msg.value >= entryFee, “Minimum entry fee required”);
这是一个原始的实现,可是它显示了可验证的随机性在上的呈现如何低落了彩票之类的合约的巨大性。以前的彩票合约需要利用哈希机制,基于时间的机制,基于区块的机制等,所有这些都容易受到进攻。

 8
 2
42
32// modifiers
73}
18    function fulfillRandomness(bytes32 _requestId, uint256 _randomness) external override {
94}
54
36}
60numberOfEntries++;
70
89}
提交数字
81}
74
4  numbers.push(_number);
53}
58require(entries[_number].add(msg.sender), “Cannot submit the same number more than once”);
14}

上,真正的随机性险些是不行能的。这是因为事务需要由网络上的多个节点举办验证才气确认。假如智能合约成果确实是随机的,那么利用该成果验证生意业务的每个节点将得出差异的功效,这意味着该生意业务将永远不会被确认。

完整代码展示:
71function rollover() public onlyOwner isState(LotteryState.Finished) {
55//functions
16
 1pragma solidity ^0.6.2;
95}
14
90
84function _payout(EnumerableSet.AddressSet storage winners) private {
阶段应限制操纵,以便只能执行答允的操纵。譬喻应该答允新提交的独一阶段是开放阶段。假如彩票封锁或竣事,条约应克制新的提交。
成立彩票智能合约
11using EnumerableSet for EnumerableSet.AddressSet;
25        return this.requestRandomness(keyHash, fee, _seed);
 9contract Lottery is Ownable{
65function drawNumber(uint256 _seed) public onlyOwner isState(LotteryState.Open) {
10    uint256 fee;
10emit NumberDrawn(_randomNumberRequestId, _randomNumber);
44constructor (uint _entryFee, uint _ownerCut, address _randomNumberGenerator) public Ownable() {
78emit NumberDrawn(_randomNumberRequestId, _randomNumber);
80_changeState(LotteryState.Finished);
 5import “@openzeppelin/contracts/utils/Address.sol”;
82}
15enum LotteryState { Open, Closed, Finished }
 9winningNumber = _randomNumber;
18uint[] numbers;
19        Lottery(requester).numberDrawn(_requestId, _randomness);
56function submitNumber(uint _number) public payable isState(LotteryState.Open) {
 4emit NumberRequested(randomNumberRequestId);
 2
22    function request(uint256 _seed) public returns(bytes32 requestId) {
52_changeState(LotteryState.Open);
 4import “@openzeppelin/contracts/utils/EnumerableSet.sol”;
输入数字
12using Address for address;
 3import “./VRFConsumerBase.sol”;
AddressSet引用OpenZeppelin EnumerableSet协定,该协定为原始范例提供附加函数。
 6import “@openzeppelin/contracts/math/SafeMath.sol”;
35_;
3    _;
16    }
33modifier isState(LotteryState _state) {
20    }
64
38modifier onlyRandomGenerator {
15            fee = _fee;
 8    address requester;
此刻当我们界说函数时,我们可以添加此修饰符以确保彩票的当前状态是我们期望的状态。
鉴于这些require声明大概在整个合约中看起来都相似,所以我们将其最小化。我们可以界说一个执行require语句的修饰符,并将其分派给我们想要的任何函数。
50ownerCut = _ownerCut;
30event NumberDrawn(bytes32 requestId, uint winningNumber);
 5}
 2_changeState(LotteryState.Closed);
43//constructor
23        require(keyHash != bytes32(0), “Must have valid key hash”);
此刻已经界说了列举,我们可以在函数中配置法则(require语句),以确保合约的当前状态切合我们的期望。
20uint public numberOfEntries;
3  require(entries[_number].add(msg.sender), “Cannot submit the same number more than once”);
2LotteryState public state;
5  numberOfEntries++;
21
93emit LotteryStateChanged(state);
2  require(msg.value >= entryFee, “Minimum entry fee required”);
86for (uint index = 0; index < winners.length(); index++) {
83
75function numberDrawn(bytes32 _randomNumberRequestId, uint _randomNumber) public onlyRandomGenerator isState(LotteryState.Closed) {
只要付出了最低入场费,任何人都可以提交号码。可是每个参赛者不能一次提交同一号码。应该答允新提交的独一状态是打开状态。
1function submitNumber(uint _number) public payable isState(LotteryState.Open) {
61payable(owner()).transfer(ownerCut);
这意味着,那些看似与智能合约完美契合,但却无法实现的观念,因为它们此刻需要随机数。
12_changeState(LotteryState.Finished);
62emit NewEntry(msg.sender, _number);
76if (_randomNumberRequestId == randomNumberRequestId) {
界说阶段
79_payout(entries[_randomNumber]);
88}
13        VRFConsumerBase(_vrfCoordinator, _link) public {
 7
 1pragma solidity >=0.6.2;
我们的彩票将在构建时将此条约的地点作为注入参数。绘制数字时,它将挪用请求函数。这要求VRF提供随机性,然后VRF向第18行的filfullRandomness提供响应。您可以在图2中看到挪用,它挪用了我们的numberDrawn彩票合约。让我们界说这些成果:
 1function drawNumber(uint256 _seed) public onlyOwner isState(LotteryState.Open) {
12    constructor(address _vrfCoordinator, address _link, bytes32 _keyHash, uint256 _fee)
1modifier isState(LotteryState _state) {
 3randomNumberRequestId = RandomNumberGenerator(randomNumberGenerator).request(_seed);
 6contract RandomNumberGenerator is VRFConsumerBase {
 9    bytes32 keyHash;

以太坊生态系统中最大的参加者之一的最新声明引起了对此问题的欢快。利用称为可验证随机函数(VRF)的系统,以太坊智能合约此刻可以生成随机数。
13using SafeMath for uint;
21uint public entryFee;
40_;
个中一个观念是彩票。
66_changeState(LotteryState.Closed);
一旦查抄完成,接下来的四行将数字添加到揣摩中,付出所有者削减的一小部门,并发出NewEntry事件。
91function _changeState(LotteryState _newState) private {
14            keyHash = _keyHash;
48require(_randomNumberGenerator.isContract(), “Random number generator must be smart contract”);
1enum LotteryState { Open, Closed, Finished }
这是我们的SubmitNumber函数:
 7import “./RandomNumberGenerator.sol”;
17

 3import “@openzeppelin/contracts/access/Ownable.sol”;
68emit NumberRequested(randomNumberRequestId);
72//rollover new lottery
28event NewEntry(address player, uint number);
39require(msg.sender == randomNumberGenerator, “Must be correct generator”);
 7function numberDrawn(bytes32 _randomNumberRequestId, uint _randomNumber) public onlyRandomGenerator isState(LotteryState.Closed) {
67randomNumberRequestId = RandomNumberGenerator(randomNumberGenerator).request(_seed);
59numbers.push(_number);
 4import “./Lottery.sol”;
24        requester = msg.sender;
87payable(winners.at(index)).transfer(balance.div(winners.length()));
假如没有人中奖,可以将彩票合约延期,从而增加头奖筹码。
51randomNumberGenerator = _randomNumberGenerator;
第7行上的numberDrawn是一旦VRF吸收到随机数后,complementRandomness会回调的函数。它确保request-id是从请求返回的ID,发失事件,,付出中奖者并将彩票的状态变动为Finished。
31
25bytes32 randomNumberRequestId;
变量entries引用了一个映射,该映射界说了揣摩的数字和已输入该数字的一组地点。界说如下:
29event NumberRequested(bytes32 requestId);
45require(_entryFee > 0, “Entry fee must be greater than 0”);
22uint public ownerCut;
11

郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。

相关文章阅读