Solidity学习记录——第四章
Solidity学习记录
第一章 创建生产僵尸的工厂
第二章 设置僵尸的攻击功能
第三章 编写DAPP所需的基础理论
第四章 完善僵尸功能
第五章 ERC721 标准和加密资产
文章目录
- Solidity学习记录
- 前言
- 一、本章主要目的
- 二、学习过程
- 1.本节课程知识点
- 2.最终代码
- 总结
前言
国庆假期,事情比较多,更新拖了两天,请见谅。
一、本章主要目的
在之前的课程,我们学习了Solidity的大部分知识,本章我们学习 payable 函数,学习如何开发可以接收其他玩家付款的DApp,并学习通过函数修饰符来完善我们的程序。
二、学习过程
1.本节课程知识点
1、payable 修饰符
payable 方法是让 Solidity 和以太坊变得如此酷的一部分 —— 它们是一种可以接收以太的特殊函数。在以太坊中, 因为钱 (Ether), 数据 (transaction payload), 以及合约代码本身都存在于以太坊。你可以在同时调用函数 并付钱给另外一个合约。如果一个函数没标记为payable, 当用户尝试发送以太时,函数将拒绝事务。
2、msg.value 是一种可以查看向合约发送了多少以太的方法,常用msg.value == XXX 来表示。如果把事务想象成一个信封,你发送到函数的参数就是信的内容。 添加一个 value 很像在信封里面放钱 —— 信件内容和钱同时发送给了接收者。
3、我们可以通过 transfer 向任何以太坊地址付钱。提现写法:
contract GetPaid is Ownable {function withdraw() external onlyOwner {owner.transfer(this.balance);}
}
4、Solidity 中最好的随机数生成器是 keccak256 哈希函数。但这个方法很容易被不诚实的节点攻击。
5、Solidity 的 keccak256 被攻击原理:
在以太坊上, 当你在和一个合约上调用函数的时候, 你会把它广播给一个节点或者在网络上的 transaction 节点们。 网络上的节点将收集很多事务, 试着成为第一个解决计算密集型数学问题的人,作为“工作证明”,然后将“工作证明”(Proof of Work, PoW)和事务一起作为一个 block 发布在网络上。
一旦一个节点解决了一个PoW, 其他节点就会停止尝试解决这个 PoW, 并验证其他节点的事务列表是有效的,然后接受这个节点转而尝试解决下一个节点。
这就让我们的随机数函数变得可利用了
如果运行一个节点,可以 只对我自己的节点 发布一个事务,且 不分享它 。 如果不是我想要的结果,我就不把这个事务包含进我要解决的下一个区块中去。我可以一直运行这个方法,直到获得了我想要的结果(类似于手游弱联网(并非实时监测是否联网)游戏,通过断网的方式来不断刷新出自己想要的东西,如:抽卡,掉落的稀有的物品等)。
2.最终代码
代码如下:
ownable.sol
//this is ownable.solpragma solidity ^0.4.19;/**
* @title Ownable
* @dev The Ownable contract has an owner address, and provides basic authorization control
* functions, this simplifies the implementation of "user permissions".
*/
contract Ownable {address private _owner;event OwnershipTransferred(address indexed previousOwner,address indexed newOwner);/*** @dev The Ownable constructor sets the original `owner` of the contract to the sender* account.*/constructor() internal {_owner = msg.sender;emit OwnershipTransferred(address(0), _owner);}/*** @return the address of the owner.*/function owner() public view returns(address) {return _owner;}/*** @dev Throws if called by any account other than the owner.*/modifier onlyOwner() {require(isOwner());_;}/*** @return true if `msg.sender` is the owner of the contract.*/function isOwner() public view returns(bool) {return msg.sender == _owner;}/*** @dev Allows the current owner to relinquish control of the contract.* @notice Renouncing to ownership will leave the contract without an owner.* It will not be possible to call the functions with the `onlyOwner`* modifier anymore.*/function renounceOwnership() public onlyOwner {emit OwnershipTransferred(_owner, address(0));_owner = address(0);}/*** @dev Allows the current owner to transfer control of the contract to a newOwner.* @param newOwner The address to transfer ownership to.*/function transferOwnership(address newOwner) public onlyOwner {_transferOwnership(newOwner);}/*** @dev Transfers control of the contract to a newOwner.* @param newOwner The address to transfer ownership to.*/function _transferOwnership(address newOwner) internal {require(newOwner != address(0));emit OwnershipTransferred(_owner, newOwner);_owner = newOwner;}
}
zombiefactory.sol
//this is zombiefactory.solpragma solidity ^0.4.19;import "./ownable.sol";contract ZombieFactory is Ownable {event NewZombie(uint zombieId, string name, uint dna);uint dnaDigits = 16;uint dnaModulus = 10 ** dnaDigits;uint cooldownTime = 1 days;struct Zombie {string name;uint dna;uint32 level;uint32 readyTime;uint16 winCount;uint16 lossCount;}Zombie[] public zombies;mapping (uint => address) public zombieToOwner;mapping (address => uint) ownerZombieCount;function _createZombie(string _name, uint _dna) internal {uint id = zombies.push(Zombie(_name, _dna, 1, uint32(now + cooldownTime), 0, 0)) - 1;zombieToOwner[id] = msg.sender;ownerZombieCount[msg.sender]++;emit NewZombie(id, _name, _dna);}function _generateRandomDna(string _str) private view returns (uint) {uint rand = uint(keccak256(abi.encodePacked(_str)));return rand % dnaModulus;}function createRandomZombie(string _name) public {require(ownerZombieCount[msg.sender] == 0);uint randDna = _generateRandomDna(_name);randDna = randDna - randDna % 100;_createZombie(_name, randDna);}}
zombiefeeding.sol
//this is zombiefeeding.solpragma solidity ^0.4.19;import "./zombiefactory.sol";contract KittyInterface {function getKitty(uint256 _id) external view returns (bool isGestating,bool isReady,uint256 cooldownIndex,uint256 nextActionAt,uint256 siringWithId,uint256 birthTime,uint256 matronId,uint256 sireId,uint256 generation,uint256 genes);
}contract ZombieFeeding is ZombieFactory {KittyInterface kittyContract;modifier ownerOf(uint _zombieId) {require(msg.sender == zombieToOwner[_zombieId]);_;}function setKittyContractAddress(address _address) external onlyOwner {kittyContract = KittyInterface(_address);}function _triggerCooldown(Zombie storage _zombie) internal {_zombie.readyTime = uint32(now + cooldownTime);}function _isReady(Zombie storage _zombie) internal view returns (bool) {return (_zombie.readyTime <= now);}function feedAndMultiply(uint _zombieId, uint _targetDna, string _species) internal ownerOf(_zombieId) {Zombie storage myZombie = zombies[_zombieId];require(_isReady(myZombie));_targetDna = _targetDna % dnaModulus;uint newDna = (myZombie.dna + _targetDna) / 2;if (keccak256(abi.encodePacked(_species)) == keccak256(abi.encodePacked("kitty"))) {newDna = newDna - newDna % 100 + 99;}_createZombie("NoName", newDna);_triggerCooldown(myZombie);}function feedOnKitty(uint _zombieId, uint _kittyId) public {uint kittyDna;(,,,,,,,,,kittyDna) = kittyContract.getKitty(_kittyId);feedAndMultiply(_zombieId, kittyDna, "kitty");}
}
zombiehelper.sol
//this is zombiehelper.solpragma solidity ^0.4.19;import "./zombiefeeding.sol";contract ZombieHelper is ZombieFeeding {uint levelUpFee = 0.001 ether;modifier aboveLevel(uint _level, uint _zombieId) {require(zombies[_zombieId].level >= _level);_;}function withdraw() external onlyOwner {address _owner = owner();_owner.transfer(address(this).balance);}function setLevelUpFee(uint _fee) external onlyOwner {levelUpFee = _fee;}function levelUp(uint _zombieId) external payable {require(msg.value == levelUpFee);zombies[_zombieId].level++;}function changeName(uint _zombieId, string _newName) external aboveLevel(2, _zombieId) ownerOf(_zombieId) {zombies[_zombieId].name = _newName;}function changeDna(uint _zombieId, uint _newDna) external aboveLevel(20, _zombieId) ownerOf(_zombieId) {zombies[_zombieId].dna = _newDna;}function getZombiesByOwner(address _owner) external view returns(uint[]) {uint[] memory result = new uint[](ownerZombieCount[_owner]);uint counter = 0;for (uint i = 0; i < zombies.length; i++) {if (zombieToOwner[i] == _owner) {result[counter] = i;counter++;}}return result;}}
zombieattack.sol
//this is zombieattack.solpragma solidity ^0.4.19;import "./zombiehelper.sol";
contract ZombieAttack is ZombieHelper {uint randNonce = 0;uint attackVictoryProbability = 70;function randMod(uint _modulus) internal returns(uint) {randNonce++;return uint(keccak256(abi.encodePacked(now, msg.sender, randNonce))) % _modulus;}function attack(uint _zombieId, uint _targetId) external ownerOf(_zombieId) {Zombie storage myZombie = zombies[_zombieId];Zombie storage enemyZombie = zombies[_targetId];uint rand = randMod(100);if (rand <= attackVictoryProbability) {myZombie.winCount++;myZombie.level++;enemyZombie.lossCount++;feedAndMultiply(_zombieId, enemyZombie.dna, "zombie");} else {myZombie.lossCount++;enemyZombie.winCount++;_triggerCooldown(myZombie);}}
}
总结
本章知识点比较少,大部分是使用之前的知识内容,本章重点知识只有两个:
1.可以使用 payable 来付款,value 用来表示付多少钱,transfer 用来转账(可以转给任何人)。
2.keccak256 函数是不安全的,有一个随机数方法是利用 oracle 来访问以太坊区块链之外的随机数函数。
Solidity学习记录——第四章相关推荐
- 《SysML精粹》学习记录--第四章
<SysML精粹>学习记录 第四章:内部模块图(Internal Block Diagram,IBD) IBD介绍 组成部分属性 引用属性 连接器 项目流 内嵌组成部分和引用 小结 第四章 ...
- 广义相对论-学习记录9-第四章-相对论性的引力理论2
第四章:相对论性的引力理论 6.变分原理推导场方程 场方程的左边为IGI_GIG,右边为IMI_MIM,作用量I=IG+IMI=I_G+I_MI=IG+IM 在平直时空中,作用量为: ...
- C语言深度剖析书籍学习记录 第四章 指针和数组
p 称为指针变量,p 里存储的内存地址处的内存称为 p 所指向的内存. 指针变量 p 里存储的任何数据都将被当作地址来处理 一个基本的数据类型(包括结构体等自定义类型)加上"*" ...
- Solidity学习记录——第二章
Solidity学习记录 第一章 创建生产僵尸的工厂 第二章 设置僵尸的攻击功能 第三章 编写DAPP所需的基础理论 第四章 完善僵尸功能 第五章 ERC721 标准和加密资产 文章目录 Solidi ...
- 《Go语言圣经》学习笔记 第四章 复合数据类型
<Go语言圣经>学习笔记 第四章 复合数据类型 目录 数组 Slice Map 结构体 JSON 文本和HTML模板 注:学习<Go语言圣经>笔记,PDF点击下载,建议看书. ...
- 《SysML精粹》学习记录--第七章
<SysML精粹>学习记录 第七章:序列图 序列图简介 序列图元素 消息 约束 组合片段 交互使用 小结 第七章:序列图 序列图简介 序列图是另一种可以用来说明系统动态行为信息的Sys ...
- 三维荧光平行因子学习记录--(四)平行因子组件导出--(一)
三维荧光平行因子学习记录–(四)平行因子组件导出–(一) 注:本文仅作为自己的学习记录以备以后复习查阅 本文参考博客链接: https://zhuanlan.zhihu.com/p/377996430 ...
- 《SysML精粹》学习记录--第六章
<SysML精粹>学习记录 第六章:活动图 活动图简介 活动图外框 活动图的关键元素 动作 对象节点 边 动作详述 控制节点 活动分区 小结 第六章:活动图 活动图简介 ...
- 计算机网络(第7版)谢希仁著 学习笔记 第四章网络层
计算机网络(第7版)谢希仁著 学习笔记 第四章网络层 第四章 网络层 4.3划分子网和构造超网 p134 4.3.1划分子网 4.3.2使用子网时分组的转发 4.3.3无分类编址CIDR(构建超网) ...
最新文章
- 图论 ---- F. The Shortest Statement (最短路的性质 + 任意两点间最短路 + 图转树)
- Netlib文件转化为mps文件
- 【深圳(活动)】70多场干货分享!价值899元的2018中国开源年会门票等你认领
- Django syncdb mysql error on localhost - (1045, Access denied for user 'ODBC'@'
- Web常见漏洞修复建议
- SpringCloud的Hystrix(二) 某消费者应用(如:ui、网关)访问的多个微服务的断路监控...
- 类数组的push方法
- 5.性能之巅 洞悉系统、企业与云计算 --- 应用程序
- 在Sql的where中使用case进行不同字段筛选|Case的2种使用方法和一种少为人知的用途...
- Excel技能培训之十五 函数使用rank,Frequency,subtotal超级表,切片器,iferor,常用错误代码
- 用于视觉问答的相互注意融合模型《Reciprocal Attention Fusion for Visual Question Answering》
- 剑指Offe6-反转链表
- Ubuntu18.04 同一个程序显示两个图标,收藏夹图标不合并问题解决
- can sdo 报文
- 基于C++的OpenCV(八)图像处理
- 基于STM32的开源简易示波器项目
- ps合成玫瑰花丛中漂亮美女照片
- WordPress php升级到7.2提示Warning: Use of undefined constant Y – assumed ‘Y’ 问题解决
- STM32开发实例 基于STM32单片机的蓝牙手环
- 哈尔滨工业大学 计算机系 张红,面向TDT的动态多文档文摘研究-哈尔滨工业大学学报.PDF...