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

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

为了存储每个玩家的彩金,我们将看到一个新的数据类型,这就是mappingmappingkey绑定到一个值。声明必须同时指定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修饰符,使它可以发送以太币到我们的智能合约。

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

原文转自这个以太坊博客