【蚂蚁链学习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。文章来源地址https://www.toymoban.com/news/detail-652002.html

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;
    }
  }
  
}

到了这里,关于【蚂蚁链学习4】授予勋章(蚂蚁链智能合约+函数部分应用+事件event)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 北大肖臻老师《区块链技术与应用》系列课程学习笔记[25]以太坊-智能合约-5

    智能合约-1 智能合约-2 智能合约-3 智能合约-4 网上竞拍第二版:由投标者自己取回出价 (1)存在的问题         重入攻击,如果有黑客写了一个如下方程序会怎么样?         这个hack_bid跟前面的那个黑客合约hack_bid合约是一样的,通过调用拍卖bid函数参与竞拍,ha

    2024年03月11日
    浏览(64)
  • 头歌平台-人工智能技术应用-实践学习与答案2(补充实训部分)

    注:这一题的输出没有很符合我的预期,所以我干脆直接改了他的print输出,用自己更喜欢的方式输出 注: 这里对字典的统计我引入了defaultdict函数(这个函数是用来新建一个键值对的),算是额外引入了一个算法库使用 测试用例: 一、 针对集体宿舍人员如何科学防控的问

    2024年02月07日
    浏览(71)
  • 蚂蚁开放联盟链合约开发入门

    蚂蚁链包含多个产品:合约体验链、开放联盟链、联盟链 合约体验链:一条本地开发体验链,供您免费体验本地开发的全流程 网址 联盟链:可以创建或加入联盟,门槛较高 网址 开放联盟链:面向企业和开发者提供的“无需搭链、快速上链、接近公链”的区块链服务网络。

    2024年02月06日
    浏览(44)
  • 什么是智能合约?智能合约的应用

    智能合约(Smart Contract)是一种基于区块链技术的自动化合约,能够自动执行合约条件,而无需人工干预。智能合约的出现为许多传统领域带来了革命性的变化,它在金融、房地产、物流、政务等领域具有广泛的应用前景。 智能合约是一种通过计算机程序实现自动执行合约的

    2024年02月16日
    浏览(38)
  • 如何在智能合约中调用另一个合约的函数

    智能合约是在区块链中被执行的一段程序,因为它们在区块链上执行,所以不依赖于任何的中心化服务器。目前最主流的智能合约编程语言是 Solidity。 在以太坊区块链中,智能合约可以和其他已经部署的智能合约进行交互。除了以太坊,其他 EVM 兼容的区块链(使用以太坊虚

    2024年01月22日
    浏览(53)
  • golang调用智能合约,获取合约函数的返回值

    如果不是只读取数据的合约函数,需要异步的执行,因此并不能直接获取到合约函数的返回值,需要等到交易执行完毕,得到确认后才能获取到合约函数的返回值。而且合约函数返回值一般是通过事件日志获取到的。 这里给出一个例子来展示我是如何获取合约函数返回值的。

    2024年03月11日
    浏览(51)
  • 智能合约 Solidity – 构造函数

    构造函数是任何面向对象的编程语言中的一种特殊方法,每当初始化类的对象时都会调用它。Solidity 则完全不同,Solidity 在智能合约内部提供了一个构造函数声明,它只在合约部署时调用一次,用于初始化合约状态。如果没有明确定义的构造函数,则编译器会创建默认构造函

    2024年02月11日
    浏览(41)
  • 蚂蚁区块链投票案例(二)---投票合约设计开发

    计划用三篇文章,一个月左右的时间来实现一个蚂蚁开放联盟链上的区块链投票案例,本文是系列第二篇。 蚂蚁区块链投票案例(一)—蚂蚁链简介 蚂蚁区块链投票案例(二)—投票合约设计开发 蚂蚁区块链投票案例(三)—Java调用部分实现(整理中) 本文将结合具体的投票案例

    2024年02月04日
    浏览(45)
  • Solidity智能合约开发 — 3.2-合约的fallback和函数重载

    每个智能合约有且仅有一个未命名的函数,称为fallback函数,没有参数且没有返回值,可见性必须是 external,且可以是 virtual的(即可以被重载),也可以有修改器 modifier。 fallback执行条件: 如果在一个合约的调用中,没有其他函数与给定的函数标识符匹配时(或没有提供调用

    2024年02月09日
    浏览(60)
  • 在前端页面上应用智能合约实现合约交互例子

    在Remix上编译和部署智能合约,本地使用vscode工具调用智能合约应用于前端界面 win10 Remix VScode Ganache-cli web3 创建新合约 InfoContract.sol 并写入以下内容: 写好合约内容之后,按照ganache-cli连接Metamask钱包里面 步骤 的内容操作。 在remix中进入DeployRun模块,选择Enviroment为Injected W

    2023年04月08日
    浏览(37)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包