资讯专栏INFORMATION COLUMN

以太坊开发实战学习-solidity语法 (三)

tianren124 / 606人阅读

摘要:接上一节,继续学习高级语法。添加语句,并且将后两位数替换为添加参数四部署以太坊实现实现我们只用编译和部署,就可以将这个合约部署到以太坊了。

接上一节,继续学习solidity高级语法。
一、使用接口

继续前面上一节 NumberInterface 的例子,我们既然将接口定义为:

contract NumberInterface {
  function getNum(address _myAddress) public view returns (uint);
}

我们可以在合约中这样使用:

contract MyContract {
  address NumberInterfaceAddress = 0xab38...;
  // ^ 这是FavoriteNumber合约在以太坊上的地址
  NumberInterface numberContract = NumberInterface(NumberInterfaceAddress);
  // 现在变量 `numberContract` 指向另一个合约对象

  function someFunction() public {
    // 现在我们可以调用在那个合约中声明的 `getNum`函数:
    uint num = numberContract.getNum(msg.sender);
    // ...在这儿使用 `num`变量做些什么
  }
}

通过这种方式,只要将您合约的可见性设置为public(公共)或external(外部),它们就可以与以太坊区块链上的任何其他合约进行交互。

实战演练

我们来建个自己的合约去读取另一个智能合约-- CryptoKitties 的内容吧!

1、我已经将代码中 CryptoKitties 合约的地址保存在一个名为 ckAddress 的变量中。在下一行中,请创建一个名为 kittyContract 的 KittyInterface,并用 ckAddress 为它初始化 —— 就像我们为 numberContract 所做的一样。

zombiefeeding.sol

pragma 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 {

  address ckAddress = 0x06012c8cf97BEaD5deAe237070F9587f8E7A266d;
  // Initialize kittyContract here using `ckAddress` from above
  KittyInterface kittyContract = KittyInterface(ckAddress);

  function feedAndMultiply(uint _zombieId, uint _targetDna) public {
    require(msg.sender == zombieToOwner[_zombieId]);
    Zombie storage myZombie = zombies[_zombieId];
    _targetDna = _targetDna % dnaModulus;
    uint newDna = (myZombie.dna + _targetDna) / 2;
    _createZombie("NoName", newDna);
  }

}
二、处理多返回值

getKitty 是我们所看到的第一个返回多个值的函数。我们来看看是如何处理的:

unction multipleReturns() internal returns(uint a, uint b, uint c) {
  return (1, 2, 3);
}

function processMultipleReturns() external {
  uint a;
  uint b;
  uint c;
  // 这样来做批量赋值:
  (a, b, c) = multipleReturns();
}

// 或者如果我们只想返回其中一个变量:
function getLastReturnValue() external {
  uint c;
  // 可以对其他字段留空:
  (,,c) = multipleReturns();
}
实战演练

是时候与 CryptoKitties 合约交互起来了!

我们来定义一个函数,从 kitty 合约中获取它的基因:

1、创建一个名为 feedOnKitty 的函数。它需要2个 uint 类型的参数,_zombieId_kittyId ,这是一个 public 类型的函数。

2、函数首先要声明一个名为 kittyDnauint

注意:在我们的 KittyInterface 中,genes 是一个 uint256 类型的变量,但是如果你记得,我们在第一课中提到过,uint 是 uint256 的别名,也就是说它们是一回事。

3、这个函数接下来调用 kittyContract.getKitty函数, 传入 _kittyId ,将返回的 genes 存储在 kittyDna 中。记住 —— getKitty 会返回一大堆变量。 (确切地说10个 - 我已经为你数过了,不错吧!)。但是我们只关心最后一个-- genes。数逗号的时候小心点哦!

4、最后,函数调用了 feedAndMultiply ,并传入了 _zombieIdkittyDna 两个参数。

zombiefeeding.sol

pragma 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 {

  address ckAddress = 0x06012c8cf97BEaD5deAe237070F9587f8E7A266d;
  KittyInterface kittyContract = KittyInterface(ckAddress);

  function feedAndMultiply(uint _zombieId, uint _targetDna) public {
    require(msg.sender == zombieToOwner[_zombieId]);
    Zombie storage myZombie = zombies[_zombieId];
    _targetDna = _targetDna % dnaModulus;
    uint newDna = (myZombie.dna + _targetDna) / 2;
    _createZombie("NoName", newDna);
  }

  // define function here
  function feedOnKitty(uint _zombieId, uint _kittyId) public {
     uint kittyDna;  // 声明一个参数

     // 多参数返回,前边不需要的可以用空格,只获取需要的返回参数
     (,,,,,,,,,kittyDna) = kittyContract.getKitty(_kittyId);

     feedAndMultiply(_zombieId, kittyDna);
  }

}
三、if语句用法

我们的功能逻辑主体已经完成了...现在让我们来添一个奖励功能吧。

这样吧,给从小猫制造出的僵尸添加些特征,以显示他们是猫僵尸。

要做到这一点,咱们在新僵尸的DNA中添加一些特殊的小猫代码。

还记得吗,第一课中我们提到,我们目前只使用16位DNA的前12位数来指定僵尸的外观。所以现在我们可以使用最后2个数字来处理“特殊”的特征。

这样吧,把猫僵尸DNA的最后两个数字设定为99(因为猫有9条命)。所以在我们这么来写代码:如果这个僵尸是一只猫变来的,就将它DNA的最后两位数字设置为99

if 语句

if语句的语法在 Solidity 中,与在 JavaScript 中差不多:

function eatBLT(string sandwich) public {
  // 看清楚了,当我们比较字符串的时候,需要比较他们的 keccak256 哈希码
  if (keccak256(sandwich) == keccak256("BLT")) {
    eat();
  }
}
实战演练

让我们在我们的僵尸代码中实现小猫的基因。

1、首先,我们修改下 feedAndMultiply 函数的定义,给它传入第三个参数:一条名为 _species 的字符串。

2、接下来,在我们计算出新的僵尸的DNA之后,添加一个 if 语句来比较 _species 和字符串 "kitty" 的 keccak256 哈希值。

3、在 if 语句中,我们用 99 替换了新僵尸DNA的最后两位数字。可以这么做:newDna = newDna - newDna%100 + 99;。

解释:假设 newDna 是 334455。那么 newDna%100 是 55,所以 newDna - newDna%100 得到 334400。最后加上 99 可得到 334499。

4、最后,我们修改了 feedOnKitty 中的函数调用。当它调用 feedAndMultiply 时,增加 “kitty” 作为最后一个参数。

zombiefeeding.sol

pragma 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 {

  address ckAddress = 0x06012c8cf97BEaD5deAe237070F9587f8E7A266d;
  KittyInterface kittyContract = KittyInterface(ckAddress);

  // Modify function definition here:
  function feedAndMultiply(uint _zombieId, uint _targetDna, string _species) public {
    require(msg.sender == zombieToOwner[_zombieId]);
    Zombie storage myZombie = zombies[_zombieId];
    _targetDna = _targetDna % dnaModulus;
    uint newDna = (myZombie.dna + _targetDna) / 2;
    // Add an if statement here,添加if语句,并且将后两位数替换为99
    if (keccak256(_species) == keccak256("kitty")) {
      newDna = newDna - newDna % 100 + 99;
    }
    _createZombie("NoName", newDna);
  }

  function feedOnKitty(uint _zombieId, uint _kittyId) public {
    uint kittyDna;
    (,,,,,,,,,kittyDna) = kittyContract.getKitty(_kittyId);
    // And modify function call here:添加参数
    feedAndMultiply(_zombieId, kittyDna, "kitty");
  }

}
四、部署以太坊实现 javaScript 实现

我们只用编译和部署 ZombieFeeding,就可以将这个合约部署到以太坊了。我们最终完成的这个合约继承自 ZombieFactory,因此它可以访问自己和父辈合约中的所有 public 方法。

我们来看一个与我们的刚部署的合约进行交互的例子, 这个例子使用了 JavaScript 和 web3.js:

var abi = /* abi generated by the compiler */
var ZombieFeedingContract = web3.eth.contract(abi)
var contractAddress = /* our contract address on Ethereum after deploying */
var ZombieFeeding = ZombieFeedingContract.at(contractAddress)

// 假设我们有我们的僵尸ID和要攻击的猫咪ID
let zombieId = 1;
let kittyId = 1;

// 要拿到猫咪的DNA,我们需要调用它的API。这些数据保存在它们的服务器上而不是区块链上。
// 如果一切都在区块链上,我们就不用担心它们的服务器挂了,或者它们修改了API,
// 或者因为不喜欢我们的僵尸游戏而封杀了我们
let apiUrl = "https://api.cryptokitties.co/kitties/" + kittyId
$.get(apiUrl, function(data) {
  let imgUrl = data.image_url
  // 一些显示图片的代码
})

// 当用户点击一只猫咪的时候:
$(".kittyImage").click(function(e) {
  // 调用我们合约的 `feedOnKitty` 函数
  ZombieFeeding.feedOnKitty(zombieId, kittyId)
})

// 侦听来自我们合约的新僵尸事件好来处理
ZombieFactory.NewZombie(function(error, result) {
  if (error) return
  // 这个函数用来显示僵尸:
  generateZombie(result.zombieId, result.name, result.dna)
})

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/24136.html

相关文章

  • 以太开发实战学习-solidity语法(二)

    摘要:以太坊开发高级语言学习。地址以太坊区块链由账户组成,你可以把它想象成银行账户。使用很安全,因为它具有以太坊区块链的安全保障除非窃取与以太坊地址相关联的私钥,否则是没有办法修改其他人的数据的。 以太坊开发高级语言学习。 一、映射(Mapping)和地址(Address) 我们通过给数据库中的僵尸指定主人, 来支持多玩家模式。 如此一来,我们需要引入2个新的数据类型:mapping(映射)...

    wemall 评论0 收藏0
  • 区块链技术学习指引

    摘要:引言给迷失在如何学习区块链技术的同学一个指引,区块链技术是随比特币诞生,因此要搞明白区块链技术,应该先了解下比特币。但区块链技术不单应用于比特币,还有非常多的现实应用场景,想做区块链应用开发,可进一步阅读以太坊系列。 本文始发于深入浅出区块链社区, 原文:区块链技术学习指引 原文已更新,请读者前往原文阅读 本章的文章越来越多,本文是一个索引帖,方便找到自己感兴趣的文章,你也可以使用左侧...

    Cristic 评论0 收藏0
  • 以太智能合约开发第一篇:IDE对solidity语法的支持

    摘要:原文发表于以太坊智能合约开发第一篇对语法的支持最近在研究以太坊智能合约的开发。是一种语法类似的高级语言,它被设计成以编译的方式生成以太坊虚拟机代码。 原文发表于:以太坊智能合约开发第一篇:IDE对solidity语法的支持 最近在研究以太坊智能合约的开发。随着研究的深入,准备写一个系列教程,将我的实际经验与大家分享,供大家参考借鉴。 solidity是什么? 以太坊官方推荐使用Sol...

    xiangzhihong 评论0 收藏0
  • 以太开发实战学习-高级Solidity理论 (五)

    摘要:接上篇文章,这里继续学习高级理论。实战演练我们来写一个返回某玩家的整个僵尸军团的函数。但这样每做一笔交易,都会改变僵尸军团的秩序。在这里开始五可支付截至目前,我们只接触到很少的函数修饰符。 接上篇文章,这里继续学习Solidity高级理论。 一、深入函数修饰符 接下来,我们将添加一些辅助方法。我们为您创建了一个名为 zombiehelper.sol 的新文件,并且将 zombiefee...

    sushi 评论0 收藏0
  • 以太开发实战学习-Web3.js(十)

    摘要:如果当前在以太坊上有大量挂起事务或者用户发送了过低的价格,我们的事务可能需要等待数个区块才能被包含进去,往往可能花费数分钟。 接上篇 Web3.js,这节课继续学习Web3.js 的相关知识。 一、发送事务 这下我们的界面能检测用户的 MetaMask 账户,并自动在首页显示它们的僵尸大军了,有没有很棒? 现在我们来看看用 send 函数来修改我们智能合约里面的数据。 相对 call...

    Scott 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<