以太坊dapp智能合约示例——通过映射用户来玩彩票

在前面的一些文章中,我们学习了以太坊智能合约编程的基础知识。现在我们来建立一个实战以太坊dapp案例:彩票。

我们彩票案例的目的是多个玩家能够通过发送钱参与彩票。玩家发送的钱越多,他赢得所有资金的机会就越大。当彩票的运营发行者决定关闭彩票后,就会选择一个优胜者,并将全部资金转给这名优胜者。

为了存储每个玩家的彩金,我们将看到一个新的数据类型,这就是mappingmappingkey绑定到一个值。声明必须同时指定key的类型和值。例如,这里我们将存储属于某个地址的钱:

1
2
3
4
5
mapping(address => uint) usersBet;

usersBet[msg.sender] = 10;

// usersBet[msg.sender] == 10

不爽的是如果索引不是线性的,即使我们知道记录的数量,也无法迭代mapping的值。因此,为了迭代我们的彩金,我们需要单独地存储玩家的数量和玩家在另一个映射中的地址列表。

所以我们将存储3个变量包括彩票运营发行者的地址:

1
2
3
4
5
6
mapping(address => uint) usersBet;
mapping(uint => address) users;
uint nbUsers = 0;
uint totalBets = 0;

address owner;

我们然后构建一个Bet函数。正常账户一样,智能合约可以操控以太坊。我们Bet函数需要有一个支付彩金的功能。当函数被调用的时候他就将投入的彩金值发送给以太坊智能合约,并将发送以太币的数量存储在msg.value

所以当函数被调用时,我们先检查发送的以太币值是否大于零即msg.value>0。然后我们将发送值存储在usersBet的映射中。如果这个玩家的彩金等于0,我们递增我们的nbUsers并存储玩家的地址,这样我们可以在关闭这一期彩票时遍历所有玩家。。

1
2
3
4
5
6
7
8
9
10
function Bet() public payable  {
if (msg.value > 0) {
if (usersBet[msg.sender] == 0) { // Is it a new player
users[nbUsers] = msg.sender;
nbUsers += 1;
}
usersBet[msg.sender] += msg.value;
totalBets += msg.value;
}
}

我们的彩票dapp的最后一部分是挑选优胜者。我们的函数EndLottery()只能由彩票的所有者访问。为了简化程序,我们将选择一个随机数在0与玩家数量之间。然后,我们将进行迭代筛选,并检查谁赢了。当玩家被发现时,我们会简单地将智能合约作为确认优胜者的一个主要依据。他将得到合约中所有的钱。

1
2
3
4
5
6
7
8
9
10
11
12
13
function EndLottery() public {
if (msg.sender == owner) {
uint sum = 0;
uint winningNumber = uint(block.blockhash(block.number-1)) % totalBets;
for (uint i=0; i < nbUsers; i++) {
sum += usersBet[users[i]];
if (sum >= winningNumber) {
selfdestruct(users[i]);
return;
}
}
}
}

一个特别的说明,我们在这个示例中使用了一个非常简单的方法来获取或取值,现实中特别是在处理钱的时候,你需要用一个更好的方法来获得真正的随机数。

下面所有的智能合约代码放在一起:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
pragma solidity ^0.4.11;

contract Lottery {

mapping(address => uint) usersBet;
mapping(uint => address) users;
uint nbUsers = 0;
uint totalBets = 0;

address owner;

function Lottery() {
owner = msg.sender;
}

function Bet() public payable {
if (msg.value > 0) {
if (usersBet[msg.sender] == 0) {
users[nbUsers] = msg.sender;
nbUsers += 1;
}
usersBet[msg.sender] += msg.value;
totalBets += msg.value;
}
}

function EndLottery() public {
if (msg.sender == owner) {
uint sum = 0;
uint winningNumber = uint(block.blockhash(block.number-1)) % totalBets + 1;
for (uint i=0; i < nbUsers; i++) {
sum += usersBet[users[i]];
if (sum >= winningNumber) {
selfdestruct(users[i]);
return;
}
}
}
}

}

所以让我们部署我们的合约并且来玩一把。我们将用我们的两个账户来发送彩金用以太坊币。作为一个功能你会看到我们可以调用函数payable进行支付。

发送了以太币后,你会发现智能合约现在成立了。

如果你从彩票运营者账户调用EntLoTyTye()函数,彩票收益将转移给优胜者,并且智能合约也将结束。

在本文中,我们使用payable修饰符,使它可以发送以太币到我们的智能合约。

  • 以太坊教程,主要介绍智能合约与dapp应用开发,适合入门。
  • 以太坊开发,主要是介绍使用node.js、mongodb、区块链、ipfs实现去中心化电商DApp实战,适合进阶。

汇智网原创翻译,转载请标明出处。原文