在前面的一些文章中,我们学习了以太坊智能合约编程的基础知识。现在我们来建立一个实战以太坊dapp案例:彩票。
我们彩票案例的目的是多个玩家能够通过发送钱参与彩票。玩家发送的钱越多,他赢得所有资金的机会就越大。当彩票的运营发行者决定关闭彩票后,就会选择一个优胜者,并将全部资金转给这名优胜者。
为了存储每个玩家的彩金,我们将看到一个新的数据类型,这就是mapping
。mapping
将key
绑定到一个值。声明必须同时指定key
的类型和值。例如,这里我们将存储属于某个地址的钱:
mapping(address => uint) usersBet;
usersBet[msg.sender] = 10;
// usersBet[msg.sender] == 10
不爽的是如果索引不是线性的,即使我们知道记录的数量,也无法迭代mapping
的值。因此,为了迭代我们的彩金,我们需要单独地存储玩家的数量和玩家在另一个映射中的地址列表。
所以我们将存储3个变量包括彩票运营发行者的地址:
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
并存储玩家的地址,这样我们可以在关闭这一期彩票时遍历所有玩家。。
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与玩家数量之间。然后,我们将进行迭代筛选,并检查谁赢了。当玩家被发现时,我们会简单地将智能合约作为确认优胜者的一个主要依据。他将得到合约中所有的钱。
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;
}
}
}
}
一个特别的说明,我们在这个示例中使用了一个非常简单的方法来获取或取值,现实中特别是在处理钱的时候,你需要用一个更好的方法来获得真正的随机数。
下面所有的智能合约代码放在一起:
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
修饰符,使它可以发送以太币到我们的智能合约。
原文转自这个以太坊博客