IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 区块链 -> 【蚂蚁链学习4】授予勋章(蚂蚁链智能合约+函数部分应用+事件event) -> 正文阅读

[区块链]【蚂蚁链学习4】授予勋章(蚂蚁链智能合约+函数部分应用+事件event)

第一章 modifier函数修饰符

函数修饰符看起来跟函数没什么不同,不过关键字 modifier 告诉编译器,这是个modifier(修饰符),而不是个function(函数)。它不能像函数那样被直接调用,只能被添加到函数定义的末尾,用以改变函数的行为。函数修饰符也可以带参数。就像函数那样使用,例如:

// 存储蚂蚁级别的映射
mapping (uint => uint) public level;

// 限定蚂蚁等级的修饰符
modifier levelThan(uint _level, uint _antId) {
  require(level[_antId] >= _level);
  _;
}

// 必须年满5级才允许发奖励
// 我们可以用如下参数调用`levelThan` 修饰符:
function prize(uint _antId) levelThan(5, _antId) {
  // 其余的程序逻辑
}

注意:prize 函数上的 levelThan 修饰符。 当你调用 prize 时,首先执行 levelThan 中的代码, 执行到 levelThan 中的 _ ; 语句时,程序再返回并执行 prize 中的代码。

实战

  1. 创建一个名为 moveCheck 的modifier,它接收2个参数, _originHouseId (uint类型) 以及 _targetHouseId (uint类型)。
  2. 运用函数逻辑确保蚂蚁搬家的两个房子 是不同的房子,_originHouseId 和 _targetHouseId 不能相同,如果一样就抛出一个错误,输出错误信息为 “不能在同一个房子来回搬东西”。
  3. 还需要确保蚂蚁搬家的原房子 houses[_originHouseId].existGoods 大于0,如果不大于0就抛出一个错误,输出错误信息为 “没东西可以搬啦,换一个房子吧”。
  4. 最后要确保蚂蚁搬家的目标房子 houses[_targetHouseId].maxGoods 大于 houses[_targetHouseId].existGoods,如果不超过就抛出一个错误,输出错误信息为 “这个房子放满啦,换一个房子吧”。
  5. 记住,修饰符的最后一行为 _;,表示修饰符调用结束后返回,并执行调用函数余下的部分。
  6. 修改 moveGoods 函数,让它带有一个 moveCheck 修饰符,调用的时候传 _originHouseId 和 _targetHouseId 参数。
pragma solidity ^0.4.20;

contract AntFamily {
  
  event NewAnt(uint indexed antId, string name, uint dna);
  event NewHouse(uint indexed houseId, string name, uint existGoods, uint maxGoods);
  
  uint dnaDigits = 12;
  uint dnaModulus = 10 ** dnaDigits;
  
  struct Ant {
    string name;
    uint dna;
    uint level;
	  uint moveCount;
  }
  
  struct House {
    string name;
    uint existGoods;
    uint maxGoods;
  }

  Ant[] public ants;
  House[] public houses;
  
  mapping (uint => identity) public antToOwner;
  mapping (identity => uint) ownerAntCount;
  mapping (uint => identity) houseToOwner;
  
  modifier moveCheck(uint _originHouseId, uint _targetHouseId) {
    require(_originHouseId != _targetHouseId, "不能在同一个房子来回搬东西");
    require(houses[_originHouseId].existGoods > 0, "没东西可以搬啦,换一个房子吧");
    require(houses[_targetHouseId].maxGoods > houses[_targetHouseId].existGoods, "这个房子放满啦,换一个房子吧");
    _;
  }
  
  function createAnt(string _name, uint _dna) {
    uint id = ants.push(Ant(_name, _dna, 1, 0)) - 1;
    antToOwner[id] = msg.sender;
    ownerAntCount[msg.sender]++;
    emit NewAnt(id, _name, _dna);
  }
  
  function createRandomAnt(string _name) {
    require(ownerAntCount[msg.sender] == 0, "只能创建一只蚂蚁");
    uint rand = uint(keccak256(_name));
    uint randDna = rand % dnaModulus;
    createAnt(_name, randDna);
  }
  
  function createHouse(string _houseName, uint _existGoods, uint _maxGoods) {
    uint houseId = houses.push(House(_houseName, _existGoods, _maxGoods)) - 1;
    houseToOwner[houseId] = msg.sender;
    emit NewHouse(houseId, _houseName, _existGoods, _maxGoods);
  }
  
  function moveGoods(uint _antId, uint _originHouseId, uint _targetHouseId) moveCheck(_originHouseId, _targetHouseId) {
    require(msg.sender == antToOwner[_antId], "只能用自己的蚂蚁搬东西");
    require(msg.sender == houseToOwner[_originHouseId], "只能给自己家搬东西");
    require(msg.sender == houseToOwner[_targetHouseId], "只能给自己家搬东西");

    House storage originHouse = houses[_originHouseId];
    House storage targetHouse = houses[_targetHouseId];
  }
  
}

第二章 私有 / 公共函数

Solidity定义的函数的属性默认为公共。这就意味着任何一方 (或其它合约) 都可以调用你合约里的函数。

显然,不是什么时候都需要这样,而且这样的合约易于受到攻击。所以将自己的函数定义为私有是一个好的编程习惯,只有当你需要外部世界调用它时才将它设置为公共。

如何定义一个私有的函数呢?

uint[] numbers; 

function _addToArray(uint _number) private {   
  numbers.push(_number); 
} 

这意味着只有我们合约中的其它函数才能够调用这个函数,给 numbers 数组添加新成员。

可以看到,在函数名字后面使用关键字 private 即可。和函数的参数类似,私有函数的名字用(_)起始。

实战

我们合约的函数 createAnt 的默认属性是公共的,这意味着任何一方都可以调用它去创建一只蚂蚁。 咱们来把它变成私有吧。

  1. 变 createAnt 为私有函数,不要忘记遵守命名的规矩哦!
  2. 我们修改了 createAnt 函数的名字,不要忘记修改调用的地方哦
  3. 我们还有几个函数是需要对外开放的,都给他们加上 public 吧。
pragma solidity ^0.4.20;

contract AntFamily {
  
  event NewAnt(uint indexed antId, string name, uint dna);
  event NewHouse(uint indexed houseId, string name, uint existGoods, uint maxGoods);
  
  uint dnaDigits = 12;
  uint dnaModulus = 10 ** dnaDigits;
  
  struct Ant {
    string name;
    uint dna;
    uint level;
	  uint moveCount;
  }
  
  struct House {
    string name;
    uint existGoods;
    uint maxGoods;
  }

  Ant[] public ants;
  House[] public houses;
  
  mapping (uint => identity) public antToOwner;
  mapping (identity => uint) ownerAntCount;
  mapping (uint => identity) houseToOwner;
  
  modifier moveCheck(uint _originHouseId, uint _targetHouseId) {
    require(_originHouseId != _targetHouseId, "不能在同一个房子来回搬东西");
    require(houses[_originHouseId].existGoods > 0, "没东西可以搬啦,换一个房子吧");
    require(houses[_targetHouseId].maxGoods > houses[_targetHouseId].existGoods, "这个房子放满啦,换一个房子吧");
    _;
  }
  
  function _createAnt(string _name, uint _dna) private {
    uint id = ants.push(Ant(_name, _dna, 1, 0)) - 1;
    antToOwner[id] = msg.sender;
    ownerAntCount[msg.sender]++;
    emit NewAnt(id, _name, _dna);
  }
  
  function createRandomAnt(string _name) public {
    require(ownerAntCount[msg.sender] == 0, "只能创建一只蚂蚁");
    uint rand = uint(keccak256(_name));
    uint randDna = rand % dnaModulus;
    _createAnt(_name, randDna);
  }
  
  function createHouse(string _houseName, uint _existGoods, uint _maxGoods) public {
    uint houseId = houses.push(House(_houseName, _existGoods, _maxGoods)) - 1;
    houseToOwner[houseId] = msg.sender;
    emit NewHouse(houseId, _houseName, _existGoods, _maxGoods);
  }
  
  function moveGoods(uint _antId, uint _originHouseId, uint _targetHouseId) public moveCheck(_originHouseId, _targetHouseId) {
    require(msg.sender == antToOwner[_antId], "只能用自己的蚂蚁搬东西");
    require(msg.sender == houseToOwner[_originHouseId], "只能给自己家搬东西");
    require(msg.sender == houseToOwner[_targetHouseId], "只能给自己家搬东西");

    House storage originHouse = houses[_originHouseId];
    House storage targetHouse = houses[_targetHouseId];
  }
  
}

第三章 函数返回值

本章中我们将学习函数的返回值,要想函数返回一个数值,可以按如下定义:

string message = "hello world"; 

function sayHello() public returns (string) {   
  return message;
}

Solidity里,函数的定义里可包含返回值的数据类型(如本例中 string)。

实战

  1. 创建一个 private 函数,命名为 _prize。它只接收一个输入变量 _antId (类型 uint), 返回一个 bool 类型的结果,告知奖励是否发放成功。

  2. 我们的函数需要声明名为 myAnt 数据类型为Ant的本地变量(这是一个 storage 型的指针)。 将其值设定为在 ants 数组中索引为_antId 所指向的值。

  3. 增加 myAnt 的 moveCount。

  4. 创建一个 if 语句来检查 myAnt 的 moveCount 是否达到 5 的倍数。

  5. 如果以上条件为 true, 我们的蚂蚁就奖励升一级!所以:

    a. 增加 myAnt 的 level。

    b. 返回 true。

  6. 添加一个 else 语句。 若没有达到 5 的倍数:

    a. 返回false。

pragma solidity ^0.4.20;

contract AntFamily {
  
  event NewAnt(uint indexed antId, string name, uint dna);
  event NewHouse(uint indexed houseId, string name, uint existGoods, uint maxGoods);
  
  uint dnaDigits = 12;
  uint dnaModulus = 10 ** dnaDigits;
  
  struct Ant {
    string name;
    uint dna;
    uint level;
	  uint moveCount;
  }
  
  struct House {
    string name;
    uint existGoods;
    uint maxGoods;
  }

  Ant[] public ants;
  House[] public houses;
  
  mapping (uint => identity) public antToOwner;
  mapping (identity => uint) ownerAntCount;
  mapping (uint => identity) houseToOwner;
  
  modifier moveCheck(uint _originHouseId, uint _targetHouseId) {
    require(_originHouseId != _targetHouseId, "不能在同一个房子来回搬东西");
    require(houses[_originHouseId].existGoods > 0, "没东西可以搬啦,换一个房子吧");
    require(houses[_targetHouseId].maxGoods > houses[_targetHouseId].existGoods, "这个房子放满啦,换一个房子吧");
    _;
  }
  
  function _createAnt(string _name, uint _dna) private {
    uint id = ants.push(Ant(_name, _dna, 1, 0)) - 1;
    antToOwner[id] = msg.sender;
    ownerAntCount[msg.sender]++;
    emit NewAnt(id, _name, _dna);
  }
  
  function createRandomAnt(string _name) public {
    require(ownerAntCount[msg.sender] == 0, "只能创建一只蚂蚁");
    uint rand = uint(keccak256(_name));
    uint randDna = rand % dnaModulus;
    _createAnt(_name, randDna);
  }
  
  function createHouse(string _houseName, uint _existGoods, uint _maxGoods) public {
    uint houseId = houses.push(House(_houseName, _existGoods, _maxGoods)) - 1;
    houseToOwner[houseId] = msg.sender;
    emit NewHouse(houseId, _houseName, _existGoods, _maxGoods);
  }
  
  function moveGoods(uint _antId, uint _originHouseId, uint _targetHouseId) public moveCheck(_originHouseId, _targetHouseId) {
    require(msg.sender == antToOwner[_antId], "只能用自己的蚂蚁搬东西");
    require(msg.sender == houseToOwner[_originHouseId], "只能给自己家搬东西");
    require(msg.sender == houseToOwner[_targetHouseId], "只能给自己家搬东西");

    House storage originHouse = houses[_originHouseId];
    House storage targetHouse = houses[_targetHouseId];
    
  }
  
  function _prize(uint _antId) private returns(bool) {
    Ant storage myAnt = ants[_antId];
    myAnt.moveCount++;
    if (myAnt.moveCount % 5 == 0) {
      myAnt.level++;
      return true;
    } else {
      return false;
    }
  }
  
}

第四章 组合起来

让我们来学习如何把每次的搬家奖励同时赋予小蚂蚁吧。

实战

让我们把蚂蚁搬家和奖励发放组合起来,并且在奖励发放后触发一个事件。

  1. 定义一个 事件 叫做 MoveResult。 它有3个参数: antId (uint) 带indexed属性, originHouseId (uint), targetHouseId (uint), 和 prizeSuccess (bool)。

  2. 修改 moveGoods 函数在最后增加

    a. 减少 originHouse 的 existGoods。

    b. 增加 targetHouse 的 existGoods。

    c. 调用刚才定义的 _prize 函数,使用一个 prizeSuccess (bool) 变量接收返回值。

    d. 在调用完 _prize 函数后 生成事件 MoveResult。

pragma solidity ^0.4.20;

contract AntFamily {
  
  event NewAnt(uint indexed antId, string name, uint dna);
  event NewHouse(uint indexed houseId, string name, uint existGoods, uint maxGoods);
  event MoveResult(uint indexed antId, uint originHouseId, uint targetHouseId, bool prizeSuccess);
  
  uint dnaDigits = 12;
  uint dnaModulus = 10 ** dnaDigits;
  
  struct Ant {
    string name;
    uint dna;
    uint level;
	  uint moveCount;
  }
  
  struct House {
    string name;
    uint existGoods;
    uint maxGoods;
  }

  Ant[] public ants;
  House[] public houses;
  
  mapping (uint => identity) public antToOwner;
  mapping (identity => uint) ownerAntCount;
  mapping (uint => identity) houseToOwner;
  
  modifier moveCheck(uint _originHouseId, uint _targetHouseId) {
    require(_originHouseId != _targetHouseId, "不能在同一个房子来回搬东西");
    require(houses[_originHouseId].existGoods > 0, "没东西可以搬啦,换一个房子吧");
    require(houses[_targetHouseId].maxGoods > houses[_targetHouseId].existGoods, "这个房子放满啦,换一个房子吧");
    _;
  }
  
  function _createAnt(string _name, uint _dna) private {
    uint id = ants.push(Ant(_name, _dna, 1, 0)) - 1;
    antToOwner[id] = msg.sender;
    ownerAntCount[msg.sender]++;
    emit NewAnt(id, _name, _dna);
  }
  
  function createRandomAnt(string _name) public {
    require(ownerAntCount[msg.sender] == 0, "只能创建一只蚂蚁");
    uint rand = uint(keccak256(_name));
    uint randDna = rand % dnaModulus;
    _createAnt(_name, randDna);
  }
  
  function createHouse(string _houseName, uint _existGoods, uint _maxGoods) public {
    uint houseId = houses.push(House(_houseName, _existGoods, _maxGoods)) - 1;
    houseToOwner[houseId] = msg.sender;
    emit NewHouse(houseId, _houseName, _existGoods, _maxGoods);
  }
  
  function moveGoods(uint _antId, uint _originHouseId, uint _targetHouseId) public moveCheck(_originHouseId, _targetHouseId) {
    require(msg.sender == antToOwner[_antId], "只能用自己的蚂蚁搬东西");
    require(msg.sender == houseToOwner[_originHouseId], "只能给自己家搬东西");
    require(msg.sender == houseToOwner[_targetHouseId], "只能给自己家搬东西");

    House storage originHouse = houses[_originHouseId];
    House storage targetHouse = houses[_targetHouseId];
    
    originHouse.existGoods--;
    targetHouse.existGoods++;
    bool prizeSuccess = _prize(_antId);
    emit MoveResult(_antId, _originHouseId, _targetHouseId, prizeSuccess);
  }
  
  function _prize(uint _antId) private returns(bool) {
    Ant storage myAnt = ants[_antId];
    myAnt.moveCount++;
    if (myAnt.moveCount % 5 == 0) {
      myAnt.level++;
      return true;
    } else {
      return false;
    }
  }
  
}
  区块链 最新文章
盘点具备盈利潜力的几大加密板块,以及潜在
阅读笔记|让区块空间成为商品,打造Web3云
区块链1.0-比特币的数据结构
Team Finance被黑分析|黑客自建Token“瞒天
区块链≠绿色?波卡或成 Web3“生态环保”标
期货从入门到高深之手动交易系列D1课
以太坊基础---区块验证
进入以太坊合并的五个数字
经典同态加密算法Paillier解读 - 原理、实现
IPFS/Filecoin学习知识科普(四)
上一篇文章      下一篇文章      查看所有文章
加:2022-04-18 17:48:21  更:2022-04-18 17:48:51 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 20:24:29-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码