以太坊開發實戰學習-solidity語法 (三)

上一節,繼續學習solidity高級語法。

1、使用接口

繼續前面上一節 NumberInterface 的例子,咱們既然將接口定義爲:java

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

咱們能夠在合約中這樣使用:web

contract MyContract {
  address NumberInterfaceAddress = 0xab38...;
  // ^ 這是FavoriteNumber合約在以太坊上的地址
  NumberInterface numberContract = NumberInterface(NumberInterfaceAddress);
  // 如今變量 `numberContract` 指向另外一個合約對象

  function someFunction() public {
    // 如今咱們能夠調用在那個合約中聲明的 `getNum`函數:
    uint num = numberContract.getNum(msg.sender);
    // ...在這兒使用 `num`變量作些什麼
  }
}

經過這種方式,只要將您合約的可見性設置爲public(公共)或external(外部),它們就能夠與以太坊區塊鏈上的任何其餘合約進行交互。segmentfault

實戰演練

咱們來建個本身的合約去讀取另外一個智能合約-- CryptoKitties 的內容吧!api

  • 一、我已經將代碼中 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);
  }

}

2、處理多返回值

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 合約中獲取它的基因:區塊鏈

  • 一、建立一個名爲 feedOnKitty 的函數。它須要2個 uint 類型的參數,_zombieId_kittyId ,這是一個 public 類型的函數。
  • 二、函數首先要聲明一個名爲 kittyDnauint
注意:在咱們的 KittyInterface 中,genes 是一個 uint256 類型的變量,可是若是你記得,咱們在第一課中提到過,uint 是 uint256 的別名,也就是說它們是一回事。
  • 三、這個函數接下來調用 kittyContract.getKitty函數, 傳入 _kittyId ,將返回的 genes 存儲在 kittyDna 中。記住 —— getKitty 會返回一大堆變量。 (確切地說10個 - 我已經爲你數過了,不錯吧!)。可是咱們只關心最後一個-- genes。數逗號的時候當心點哦!
  • 四、最後,函數調用了 feedAndMultiply ,並傳入了 _zombieIdkittyDna 兩個參數。

zombiefeeding.solui

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

}

3、if語句用法

咱們的功能邏輯主體已經完成了...如今讓咱們來添一個獎勵功能吧。url

這樣吧,給從小貓製造出的殭屍添加些特徵,以顯示他們是貓殭屍。

要作到這一點,我們在新殭屍的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();
  }
}

實戰演練

讓咱們在咱們的殭屍代碼中實現小貓的基因。

  • 一、首先,咱們修改下 feedAndMultiply 函數的定義,給它傳入第三個參數:一條名爲 _species 的字符串。
  • 二、接下來,在咱們計算出新的殭屍的DNA以後,添加一個 if 語句來比較 _species 和字符串 "kitty" 的 keccak256 哈希值。
  • 三、在 if 語句中,咱們用 99 替換了新殭屍DNA的最後兩位數字。能夠這麼作:newDna = newDna - newDna%100 + 99;。
  • 解釋:假設 newDna 是 334455。那麼 newDna%100 是 55,因此 newDna - newDna%100 獲得 334400。最後加上 99 可獲得 334499。
  • 四、最後,咱們修改了 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");
  }

}

4、部署以太坊實現

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)
})
相關文章
相關標籤/搜索