学习区块链(六)--创建僵尸军团进阶Ⅰ

在前面两章的介绍中,我们基本学会了solidty的基本语法,包括数据类型,函数的创建及其属性及事件,下面我们将继续深入学习solidity和Etherun的结合使用。

一.映射
首先介绍一个很重要的概念:地址,以太坊区块链由 account (账户)组成,你可以把它想象成银行账户。一个帐户的余额是 以太 (在以太坊区块链上使用的币种),你可以和其他帐户之间支付和接受以太币,就像你的银行帐户可以电汇资金到其他银行帐户一样。

每个帐户都有一个“地址”,你可以把它想象成银行账号。这是账户唯一的标识符,它看起来长这样:
0x5Dcf545Bfb5Cfe2313864DC3FAFa53c6003938F4
这是小弟的地址,欢迎打赏转账测试,哈哈!
如果我们需要wei僵尸指定主人,通过地址生成僵尸的id是个不错的主意,当用户通过与我们的应用程序交互来创建新的僵尸时,新僵尸的所有权被设置到调用者的太坊地址名下。

为了存储僵尸的所有权,我们会使用到两个映射:一个记录僵尸拥有者的地址,另一个记录某 ID 所拥有僵尸的数量。

1.创建一个叫做 zombieToOwner 的映射。其键是一个uint(我们将根据它的 id 存储和查找僵尸),值为 adress。映射属性为public。

   mapping (uint => address) public zombieToOwner;

2.创建一个名为 ownerZombieCount 的映射,其中键是一个 address,值是 uint。

 mapping (address => uint) ownerZombieCount; 

这两部操作相当于Java的map,zombieToOwner这个映射输入僵尸id就能找到僵尸主人的地址,即address = map.get(“id”); 而ownerZombieCount 输入用户地址能获取他拥有僵尸的数量,即count = map.get(“address”);

二 .Msg.sender

在 Solidity 中,功能执行始终需要从外部调用者开始。 一个合约只会在区块链上什么也不做,除非有人调用其中的函数。调用者就是 msg.sender,msg.sender就是合约调用者的地址。

我们来修改 _createZombie 方法,将僵尸分配给函数调用者:

首先,在得到新的僵尸 id 后,更新 zombieToOwner 映射,在 id 下面存入 msg.sender。

然后,我们为这个 msg.sender 名下的 ownerZombieCount 加 1。

    function _createZombie(string _name, uint _dna) private {
        uint id = zombies.push(Zombie(_name, _dna)) - 1;
        // 从这里开始
        zombieToOwner[id] = msg.sender;
        ownerZombieCount[msg.sender]++;
        NewZombie(id, _name, _dna);
    }

有了前面和map的对比,这里很好理解。

三.require

我们成功让用户通过调用 createRandomZombie 并输入一个名字来创建新的僵尸。 但是,如果用户能持续调用这个函数来创建出无限多个僵尸加入他们的军团,这游戏就太没意思了!
根据以往的开发经验,此时就使用if()去判断一个地址是否创建一个僵尸,创建过了就不再次创建,而在solidity中,我们是用require来更简洁的实现这一功能:
我们在createRandomZombie方法开始的时候使用 require(ownerZombieCount[msg.sender] == 0);来判断用户是否已经创建了僵尸,如果ownerZombieCount[msg.sender]不等于0就会抛出一个错误不再继续执行合约!

    function createRandomZombie(string _name) public {
        require(ownerZombieCount[msg.sender] == 0);
        uint randDna = _generateRandomDna(_name);
        _createZombie(_name, randDna);
    }

本章完整代码:

pragma solidity ^0.4.19;

contract ZombieFactory {

    event NewZombie(uint zombieId, string name, uint dna);

    uint dnaDigits = 16;
    uint dnaModulus = 10 ** dnaDigits;

    struct Zombie {
        string name;
        uint dna;
    }

    Zombie[] public zombies;

    mapping (uint => address) public zombieToOwner;
    mapping (address => uint) ownerZombieCount;

    function _createZombie(string _name, uint _dna) private {
        uint id = zombies.push(Zombie(_name, _dna)) - 1;
        zombieToOwner[id] = msg.sender;
        ownerZombieCount[msg.sender]++;
        NewZombie(id, _name, _dna);
    }

    function _generateRandomDna(string _str) private view returns (uint) {
        uint rand = uint(keccak256(_str));
        return rand % dnaModulus;
    }

    function createRandomZombie(string _name) public {
        require(ownerZombieCount[msg.sender] == 0);
        uint randDna = _generateRandomDna(_name);
        _createZombie(_name, randDna);
    }

}
阅读更多

更多精彩内容