文章目录

  • 第一章 modifier函数修饰符
    • 实战
  • 第二章 私有 / 公共函数
    • 实战
  • 第三章 函数返回值
    • 实战
  • 第四章 组合起来
    • 实战

第一章 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;}}}

【蚂蚁链学习4】授予勋章(蚂蚁链智能合约+函数部分应用+事件event)相关推荐

  1. 区块链学习(8) EOS环境安装和智能合约部署实战(绝对干货!)

    硬件配置 操作系统要求 1. Amazon 2017.09 and higher 2. Centos 7 3. Fedora 25 and higher (Fedora 27 recommended) ...

  2. 区块链技术最佳的监管方式是智能合约监管智能合约

    区块链最新消息 1.在国内首部<区块链安全生存指南>发布 最新消息:比特大.长亭科技和ConsenSys陆联手发布了全国首部<区块链安全生存指南>.该指南围绕区块链技术安全,对 ...

  3. 区块链学习笔记:DAY01 区块链的技术原理

    其实很早之前就听过区块链,也看过有关区块链的介绍,那个时候的理解主要还是一句话:分布式记账 然后开始关注比特币,听了有几年了,对于其来历.用途其实一直都是一知半解. 这次的课算是第一次以一个学员的身份 ...

  4. 区块链学习笔记:D02 区块链的技术发展历史和趋势

    对于区块链的技术发展历史,其实在我的印象中也就对比特币有所了解,也听过什么火币之类的玩意,但是具体是什么.怎么运作的就不清楚了... 这次的内容首先是讲解了区块链的技术演进,一张图一目了然,虽然里面涉 ...

  5. 区块链学习笔记(初识区块链)

    区块链 区块链比比特币更加迷人,区块链具有革命性的意义,它是一个创造信任的机器 AI是生产力的提升,区块链是生产关系的变更,可能使人类的生产结构产生重大变革,淡化国家的权利机构 比特币按字节数收费 一 ...

  6. 10本区块链热门图书(应用开发、智能合约等)免费送!

    欢迎访问网易云社区,了解更多网易技术产品运营经验. "互联网之后就是区块链时代,区块链是实现未来跟踪经济的关键技术."世界上真的存在 100% 去中心化的系统吗?区块链到底是什么? ...

  7. 区块链开发入门:基于以太坊智能合约构建 ICO DApp

    写给前端开发者的第一本区块链开发入门指南,通过从 0 到 1 实战开发一个 ICO DApp 项目(基于 V 神的 DAICO 设计思想),深入掌握区块链及以太坊技术. 为什么要选择区块链开发? 未来 ...

  8. GRE:区块链将引领传统保险走向风险智能合约的时代变革

    点击上方 "蓝色字" 可关注我们! 编辑:铅笔盒 北京时间3月28日,每月两次的行业盛会[ ICT创新创业"深度脑洞聚会"]在上海举行,目前已举办235期.历时 ...

  9. 区块链学习(6)区块链

    写了几篇区块链的学习笔记,今天来写写比特币中的区块链.比特币中区块链是由包含交易信息的区块从后向前有序链接起来的数据结构.每个区块从后向前有序地链接在这个链条里,每个区块都指向前一个区块. 区块结构 ...

最新文章

  1. Swift 4 无限滚动轮播图(UICollectionView实现)
  2. 机器学习中梯度下降法和牛顿法的比较
  3. 7.组件连线(贝塞尔曲线)--从零起步实现基于Html5的WEB设计器Jquery插件(含源码)...
  4. Java8 函数式对齐约定————Eclipse自定义代码风格
  5. jQuery获取div的背景颜色 How to get background color of div?
  6. Bailian4039 IP地址转换【进制】
  7. 基于微信小程序点餐系统的设计与实现
  8. 用lordpe给一个程序添加dll时提示找不到API怎么办?
  9. 织梦dedecms调用热门搜索关键词的方法
  10. 三菱PLC基础知识 辅助继电器M
  11. Java程序员的工资标准是多少
  12. matlab求dfa指数,关于使用MF-DFA方法计算广义Hurst指数的MATLAB操作问题
  13. 移动开发需要关心的热门技术(1)
  14. Kubernetes 安全容器技术 kata gvisor
  15. HTML5印章绘制电子签章图片,中文英文椭圆章、中文英文椭圆印章 电子签章图片采集
  16. JavaSwing——利息计算器
  17. android6.0屏蔽home键,android 禁用home键
  18. Python爬虫十六式 - 第四式: 使用Xpath提取网页内容
  19. 2011年11月1日(梁)
  20. 销售订单发票计划导入

热门文章

  1. ThinkPHP中空模型M()的应用query(),execute()
  2. 为什么会有共享充电宝,它又是什么?怎么用?
  3. 之后的计划 我的日常日记系列。
  4. 数据结构——停车场系统
  5. 回文树/回文自动机学习
  6. 陈赫头像java_好甜蜜!鹿晗微信头像是陈赫,三个爷们像极了“极挑男人帮”...
  7. Web服务器踩坑之旅03:解析HTTP请求报文
  8. iOS之SDWebimage下载图片链接带中文处理
  9. 设字符型变量 x 的值是 064,表达式....的值是
  10. 如何测试web网站?