成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

以太坊開(kāi)發(fā)實(shí)戰(zhàn)學(xué)習(xí)-合約安全(八)

UsherChen / 1134人閱讀

摘要:合約安全增強(qiáng)溢出和下溢我們將來(lái)學(xué)習(xí)你在編寫(xiě)智能合約的時(shí)候需要注意的一個(gè)主要的安全特性防止溢出和下溢。實(shí)戰(zhàn)演練給加上一些標(biāo)簽把這里變成標(biāo)準(zhǔn)的注釋把一個(gè)管理轉(zhuǎn)移僵尸所有權(quán)的合約符合對(duì)標(biāo)準(zhǔn)草案的實(shí)現(xiàn)

通過(guò)上一節(jié)的學(xué)習(xí),我們完成了 ERC721 的實(shí)現(xiàn)。并不是很復(fù)雜,對(duì)吧?很多類似的以太坊概念,當(dāng)你只聽(tīng)人們談?wù)撍鼈兊臅r(shí)候,會(huì)覺(jué)得很復(fù)雜。所以最簡(jiǎn)單的理解方式就是你自己來(lái)實(shí)現(xiàn)它。
一、預(yù)防溢出

不過(guò)要記住那只是最簡(jiǎn)單的實(shí)現(xiàn)。還有很多的特性我們也許想加入到我們的實(shí)現(xiàn)中來(lái),比如一些額外的檢查,來(lái)確保用戶不會(huì)不小心把他們的僵尸轉(zhuǎn)移給0 地址(這被稱作 “燒幣”, 基本上就是把代幣轉(zhuǎn)移到一個(gè)誰(shuí)也沒(méi)有私鑰的地址,讓這個(gè)代幣永遠(yuǎn)也無(wú)法恢復(fù))。 或者在 DApp 中加入一些基本的拍賣(mài)邏輯。(你能想出一些實(shí)現(xiàn)的方法么?)

但是為了讓我們的課程不至于離題太遠(yuǎn),所以我們只專注于一些基礎(chǔ)實(shí)現(xiàn)。如果你想學(xué)習(xí)一些更深層次的實(shí)現(xiàn),可以在這個(gè)教程結(jié)束后,去看看 OpenZeppelin 的 ERC721 合約。

合約安全增強(qiáng):溢出和下溢

我們將來(lái)學(xué)習(xí)你在編寫(xiě)智能合約的時(shí)候需要注意的一個(gè)主要的安全特性:防止溢出和下溢。

什么是溢出(overflow)?

假設(shè)我們有一個(gè) uint8, 只能存儲(chǔ)8 bit數(shù)據(jù)。這意味著我們能存儲(chǔ)的最大數(shù)字就是二進(jìn)制 11111111 (或者說(shuō)十進(jìn)制的 2^8 - 1 = 255).

來(lái)看看下面的代碼。最后 number 將會(huì)是什么值?

uint8 number = 255;
number++;

在這個(gè)例子中,我們導(dǎo)致了溢出 — 雖然我們加了1, 但是 number 出乎意料地等于 0了。 (如果你給二進(jìn)制 111111111, 它將被重置為 00000000,就像鐘表從 23:59 走向 00:00)。

下溢(underflow)也類似,如果你從一個(gè)等于 0 的 uint8 減去 1, 它將變成 255 (因?yàn)?uint 是無(wú)符號(hào)的,其不能等于負(fù)數(shù))。

雖然我們?cè)谶@里不使用 uint8,而且每次給一個(gè) uint256 加 1 也不太可能溢出 (2^256 真的是一個(gè)很大的數(shù)了),在我們的合約中添加一些保護(hù)機(jī)制依然是非常有必要的,以防我們的 DApp 以后出現(xiàn)什么異常情況。

使用 SafeMath

為了防止這些情況,OpenZeppelin 建立了一個(gè)叫做 SafeMath 的 庫(kù)(library),默認(rèn)情況下可以防止這些問(wèn)題。

不過(guò)在我們使用之前…… 什么叫做庫(kù)?

一個(gè)庫(kù)是 Solidity 中一種特殊的合約。其中一個(gè)有用的功能是給原始數(shù)據(jù)類型增加一些方法。

比如,使用 SafeMath 庫(kù)的時(shí)候,我們將使用 using SafeMath for uint256 這樣的語(yǔ)法。 SafeMath 庫(kù)有四個(gè)方法 — add, sub, mul, 以及 div?,F(xiàn)在我們可以這樣來(lái)讓 uint256 調(diào)用這些方法:

using SafeMath for uint256;

uint256 a = 5;
uint256 b = a.add(3); // 5 + 3 = 8
uint256 c = a.mul(2); // 5 * 2 = 10

我們將在下一章來(lái)學(xué)習(xí)這些方法,不過(guò)現(xiàn)在我們先將 SafeMath 庫(kù)添加進(jìn)我們的合約。

實(shí)戰(zhàn)演練

我們已經(jīng)幫你把 OpenZeppelin 的 SafeMath 庫(kù)包含進(jìn) safemath.sol了,如果你想看一下代碼的話,現(xiàn)在可以看看,不過(guò)我們下一節(jié)將深入進(jìn)去。

首先我們來(lái)告訴我們的合約要使用 SafeMath。我們將在我們的 ZombieFactory 里調(diào)用,這是我們的基礎(chǔ)合約 — 這樣其他所有繼承出去的子合約都可以使用這個(gè)庫(kù)了。

1、將 safemath.sol 引入到 zombiefactory.sol.

2、添加定義: using SafeMath for uint256;.

zombiefactory.sol

pragma solidity ^0.4.19;

import "./ownable.sol";
// 1. 在這里引入
import "./safemath.sol";

contract ZombieFactory is Ownable {

  // 2. 在這里定義 using safemath 
  using SafeMath for uint 256;
  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]++;
    NewZombie(id, _name, _dna);
  }

  function _generateRandomDna(string _str) private view returns (uint) {
    uint rand = uint(keccak256(_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);
  }

}
二、SafeMath

來(lái)看看 SafeMath 的部分代碼:

library SafeMath {

  function mul(uint256 a, uint256 b) internal pure returns (uint256) {
    if (a == 0) {
      return 0;
    }
    uint256 c = a * b;
    assert(c / a == b);
    return c;
  }

  function div(uint256 a, uint256 b) internal pure returns (uint256) {
    // assert(b > 0); // Solidity automatically throws when dividing by 0
    uint256 c = a / b;
    // assert(a == b * c + a % b); // There is no case in which this doesn"t hold
    return c;
  }

  function sub(uint256 a, uint256 b) internal pure returns (uint256) {
    assert(b <= a);
    return a - b;
  }

  function add(uint256 a, uint256 b) internal pure returns (uint256) {
    uint256 c = a + b;
    assert(c >= a);
    return c;
  }
}

首先我們有了 library 關(guān)鍵字 — 庫(kù)和 合約很相似,但是又有一些不同。 就我們的目的而言,庫(kù)允許我們使用 using 關(guān)鍵字,它可以自動(dòng)把庫(kù)的所有方法添加給一個(gè)數(shù)據(jù)類型:

using SafeMath for uint;
// 這下我們可以為任何 uint 調(diào)用這些方法了
uint test = 2;
test = test.mul(3); // test 等于 6 了
test = test.add(5); // test 等于 11 了

注意 mul 和 add 其實(shí)都需要兩個(gè)參數(shù)。 在我們聲明了 using SafeMath for uint 后,我們用來(lái)調(diào)用這些方法的 uint 就自動(dòng)被作為第一個(gè)參數(shù)傳遞進(jìn)去了(在此例中就是 test)

我們來(lái)看看 add 的源代碼看 SafeMath 做了什么:

function add(uint256 a, uint256 b) internal pure returns (uint256) {
  uint256 c = a + b;
  assert(c >= a);
  return c;
}

基本上 add 只是像 + 一樣對(duì)兩個(gè) uint 相加, 但是它用一個(gè) assert 語(yǔ)句來(lái)確保結(jié)果大于 a。這樣就防止了溢出。

assert和require區(qū)別

assertrequire 相似,若結(jié)果為否它就會(huì)拋出錯(cuò)誤。 assert 和 require 區(qū)別在于,require 若失敗則會(huì)返還給用戶剩下的 gas, assert 則不會(huì)。所以大部分情況下,你寫(xiě)代碼的時(shí)候會(huì)比較喜歡 require,assert 只在代碼可能出現(xiàn)嚴(yán)重錯(cuò)誤的時(shí)候使用,比如 uint 溢出。

所以簡(jiǎn)而言之, SafeMath 的 add, sub, mul, 和 div 方法只做簡(jiǎn)單的四則運(yùn)算,然后在發(fā)生溢出或下溢的時(shí)候拋出錯(cuò)誤。

在我們的代碼里使用SafeMath。

為了防止溢出和下溢,我們可以在我們的代碼里找 +, -, *, 或 /,然后替換為 add, sub, mul, div.

比如,與其這樣做:

myUint++;

我們這樣做:

myUint = myUint.add(1);
實(shí)戰(zhàn)演練

ZombieOwnership 中有兩個(gè)地方用到了數(shù)學(xué)運(yùn)算,來(lái)替換成 SafeMath 方法把。

1、將 ++ 替換成 SafeMath 方法。

2、將 -- 替換成 SafeMath 方法。

ZombieOwnership

pragma solidity ^0.4.19;

import "./zombieattack.sol";
import "./erc721.sol";
import "./safemath.sol";

contract ZombieOwnership is ZombieAttack, ERC721 {

  using SafeMath for uint256;

  mapping (uint => address) zombieApprovals;

  function balanceOf(address _owner) public view returns (uint256 _balance) {
    return ownerZombieCount[_owner];
  }

  function ownerOf(uint256 _tokenId) public view returns (address _owner) {
    return zombieToOwner[_tokenId];
  }

  function _transfer(address _from, address _to, uint256 _tokenId) private {
    // 1. 替換成 SafeMath 的 `add`
    // ownerZombieCount[_to].add(1);  // 這種寫(xiě)法錯(cuò)誤,沒(méi)有賦值
    ownerZombieCount[_to] = ownerZombieCount[_to].add(1);

    // 2. 替換成 SafeMath 的 `sub`
    // ownerZombieCount[_from].sub(1); // 這種寫(xiě)法錯(cuò)誤
    ownerZombieCount[_from] = ownerZombieCount[_from].sub(1);
    
    zombieToOwner[_tokenId] = _to;
    Transfer(_from, _to, _tokenId);
  }

  function transfer(address _to, uint256 _tokenId) public onlyOwnerOf(_tokenId) {
    _transfer(msg.sender, _to, _tokenId);
  }

  function approve(address _to, uint256 _tokenId) public onlyOwnerOf(_tokenId) {
    zombieApprovals[_tokenId] = _to;
    Approval(msg.sender, _to, _tokenId);
  }

  function takeOwnership(uint256 _tokenId) public {
    require(zombieApprovals[_tokenId] == msg.sender);
    address owner = ownerOf(_tokenId);
    _transfer(owner, msg.sender, _tokenId);
  }
}

其他類型

太好了,這下我們的 ERC721 實(shí)現(xiàn)不會(huì)有溢出或者下溢了。

回頭看看我們?cè)谥罢n程寫(xiě)的代碼,還有其他幾個(gè)地方也有可能導(dǎo)致溢出或下溢。

比如, 在 ZombieAttack 里面我們有:

myZombie.winCount++;
myZombie.level++;
enemyZombie.lossCount++;

我們同樣應(yīng)該在這些地方防止溢出。(通常情況下,總是使用 SafeMath 而不是普通數(shù)學(xué)運(yùn)算是個(gè)好主意,也許在以后 Solidity 的新版本里這點(diǎn)會(huì)被默認(rèn)實(shí)現(xiàn),但是現(xiàn)在我們得自己在代碼里實(shí)現(xiàn)這些額外的安全措施)。

不過(guò)我們遇到個(gè)小問(wèn)題 — winCount 和 lossCount 是 uint16, 而 level 是 uint32。 所以如果我們用這些作為參數(shù)傳入 SafeMath 的 add 方法。 它實(shí)際上并不會(huì)防止溢出,因?yàn)樗鼤?huì)把這些變量都轉(zhuǎn)換成 uint256:

function add(uint256 a, uint256 b) internal pure returns (uint256) {
  uint256 c = a + b;
  assert(c >= a);
  return c;
}

// 如果我們?cè)赻uint8` 上調(diào)用 `.add`。它將會(huì)被轉(zhuǎn)換成 `uint256`.
// 所以它不會(huì)在 2^8 時(shí)溢出,因?yàn)?256 是一個(gè)有效的 `uint256`.

這就意味著,我們需要再實(shí)現(xiàn)兩個(gè)庫(kù)來(lái)防止 uint16 和 uint32 溢出或下溢。我們可以將其命名為 SafeMath16SafeMath32。

代碼將和 SafeMath 完全相同,除了所有的 uint256 實(shí)例都將被替換成 uint32 或 uint16。

我們已經(jīng)將這些代碼幫你寫(xiě)好了,打開(kāi) safemath.sol 合約看看代碼吧。

現(xiàn)在我們需要在 ZombieFactory 里使用它們。

safemath.sol

pragma solidity ^0.4.18;

/**
 * @title SafeMath
 * @dev Math operations with safety checks that throw on error
 */
library SafeMath {

  /**
  * @dev Multiplies two numbers, throws on overflow.
  */
  function mul(uint256 a, uint256 b) internal pure returns (uint256) {
    if (a == 0) {
      return 0;
    }
    uint256 c = a * b;
    assert(c / a == b);
    return c;
  }

  /**
  * @dev Integer division of two numbers, truncating the quotient.
  */
  function div(uint256 a, uint256 b) internal pure returns (uint256) {
    // assert(b > 0); // Solidity automatically throws when dividing by 0
    uint256 c = a / b;
    // assert(a == b * c + a % b); // There is no case in which this doesn"t hold
    return c;
  }

  /**
  * @dev Substracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
  */
  function sub(uint256 a, uint256 b) internal pure returns (uint256) {
    assert(b <= a);
    return a - b;
  }

  /**
  * @dev Adds two numbers, throws on overflow.
  */
  function add(uint256 a, uint256 b) internal pure returns (uint256) {
    uint256 c = a + b;
    assert(c >= a);
    return c;
  }
}

/**
 * @title SafeMath32
 * @dev SafeMath library implemented for uint32
 */
library SafeMath32 {

  function mul(uint32 a, uint32 b) internal pure returns (uint32) {
    if (a == 0) {
      return 0;
    }
    uint32 c = a * b;
    assert(c / a == b);
    return c;
  }

  function div(uint32 a, uint32 b) internal pure returns (uint32) {
    // assert(b > 0); // Solidity automatically throws when dividing by 0
    uint32 c = a / b;
    // assert(a == b * c + a % b); // There is no case in which this doesn"t hold
    return c;
  }

  function sub(uint32 a, uint32 b) internal pure returns (uint32) {
    assert(b <= a);
    return a - b;
  }

  function add(uint32 a, uint32 b) internal pure returns (uint32) {
    uint32 c = a + b;
    assert(c >= a);
    return c;
  }
}

/**
 * @title SafeMath16
 * @dev SafeMath library implemented for uint16
 */
library SafeMath16 {

  function mul(uint16 a, uint16 b) internal pure returns (uint16) {
    if (a == 0) {
      return 0;
    }
    uint16 c = a * b;
    assert(c / a == b);
    return c;
  }

  function div(uint16 a, uint16 b) internal pure returns (uint16) {
    // assert(b > 0); // Solidity automatically throws when dividing by 0
    uint16 c = a / b;
    // assert(a == b * c + a % b); // There is no case in which this doesn"t hold
    return c;
  }

  function sub(uint16 a, uint16 b) internal pure returns (uint16) {
    assert(b <= a);
    return a - b;
  }

  function add(uint16 a, uint16 b) internal pure returns (uint16) {
    uint16 c = a + b;
    assert(c >= a);
    return c;
  }
}
實(shí)戰(zhàn)演練

分配:

1、聲明我們將為 uint32 使用SafeMath32。

2、聲明我們將為 uint16 使用SafeMath16。

3、在 ZombieFactory 里還有一處我們也應(yīng)該使用 SafeMath 的方法, 我們已經(jīng)在那里留了注釋提醒你。

zombiefactory.sol

pragma solidity ^0.4.19;

import "./ownable.sol";
import "./safemath.sol";

contract ZombieFactory is Ownable {

  using SafeMath for uint256;
  // 1. 為 uint32 聲明 使用 SafeMath32
    using SafeMath32 for uint32;
  // 2. 為 uint16 聲明 使用 SafeMath16
   using SafeMath16 for uint16;

  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 {
    // 注意: 我們選擇不處理2038年問(wèn)題,所以不用擔(dān)心 readyTime 的溢出
    // 反正在2038年我們的APP早完蛋了
    uint id = zombies.push(Zombie(_name, _dna, 1, uint32(now + cooldownTime), 0, 0)) - 1;
    zombieToOwner[id] = msg.sender;
    // 3. 在這里使用 SafeMath 的 `add` 方法:
    // ownerZombieCount[msg.sender]++;
    ownerZombieCount[msg.sender] = ownerZombieCount[msg.sender].add(1);
    NewZombie(id, _name, _dna);
  }

  function _generateRandomDna(string _str) private view returns (uint) {
    uint rand = uint(keccak256(_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);
  }

}

現(xiàn)在,讓我們也順手把zombieattack.sol文件里邊的方法也修改為safeMath 形式。

zombieattack.sol

pragma solidity ^0.4.19;

import "./zombiehelper.sol";

contract ZombieBattle is ZombieHelper {
  uint randNonce = 0;
  uint attackVictoryProbability = 70;

  function randMod(uint _modulus) internal returns(uint) {
    // 這兒有一個(gè)
    randNonce = randNonce.add(1);
    return uint(keccak256(now, msg.sender, randNonce)) % _modulus;
  }

  function attack(uint _zombieId, uint _targetId) external onlyOwnerOf(_zombieId) {
    Zombie storage myZombie = zombies[_zombieId];
    Zombie storage enemyZombie = zombies[_targetId];
    uint rand = randMod(100);
    if (rand <= attackVictoryProbability) {
      // 這里有三個(gè)
      myZombie.winCount = myZombie.winCount.add(1);
      myZombie.level = myZombie.level.add(1);
      enemyZombie.lossCount = enemyZombie.lossCount.add(1);
      feedAndMultiply(_zombieId, enemyZombie.dna, "zombie");
    } else {
      // 這兒還有倆哦
      myZombie.lossCount = myZombie.lossCount.add(1);
      enemyZombie.winCount = enemyZombie.winCount.add(1);
      _triggerCooldown(myZombie);
    }
  }
}
三、注釋

尸游戲的 Solidity 代碼終于完成啦。

在以后的課程中,我們將學(xué)習(xí)如何將游戲部署到以太坊,以及如何和 Web3.js 交互。

不過(guò)在你離開(kāi)這節(jié)之前,我們來(lái)談?wù)勅绾?給你的代碼添加注釋.

注釋語(yǔ)法

Solidity 里的注釋和 JavaScript 相同。在我們的課程中你已經(jīng)看到了不少單行注釋了:

// 這是一個(gè)單行注釋,可以理解為給自己或者別人看的筆記

只要在任何地方添加一個(gè) // 就意味著你在注釋。如此簡(jiǎn)單所以你應(yīng)該經(jīng)常這么做。

不過(guò)我們也知道你的想法:有時(shí)候單行注釋是不夠的。畢竟你生來(lái)話癆。

contract CryptoZombies { 
  /* 這是一個(gè)多行注釋。我想對(duì)所有花時(shí)間來(lái)嘗試這個(gè)編程課程的人說(shuō)聲謝謝。
  它是免費(fèi)的,并將永遠(yuǎn)免費(fèi)。但是我們依然傾注了我們的心血來(lái)讓它變得更好。

   要知道這依然只是區(qū)塊鏈開(kāi)發(fā)的開(kāi)始而已,雖然我們已經(jīng)走了很遠(yuǎn),
   仍然有很多種方式來(lái)讓我們的社區(qū)變得更好。
   如果我們?cè)谀膫€(gè)地方出了錯(cuò),歡迎在我們的 github 提交 PR 或者 issue 來(lái)幫助我們改進(jìn):
    https://github.com/loomnetwork/cryptozombie-lessons

    或者,如果你有任何的想法、建議甚至僅僅想和我們打聲招呼,歡迎來(lái)我們的電報(bào)群:
     https://t.me/loomnetworkcn
  */
}

所以我們有了多行注釋:

contract CryptoZombies { 
  /* 這是一個(gè)多行注釋。我想對(duì)所有花時(shí)間來(lái)嘗試這個(gè)編程課程的人說(shuō)聲謝謝。
  它是免費(fèi)的,并將永遠(yuǎn)免費(fèi)。但是我們依然傾注了我們的心血來(lái)讓它變得更好。

   要知道這依然只是區(qū)塊鏈開(kāi)發(fā)的開(kāi)始而已,雖然我們已經(jīng)走了很遠(yuǎn),
   仍然有很多種方式來(lái)讓我們的社區(qū)變得更好。
   如果我們?cè)谀膫€(gè)地方出了錯(cuò),歡迎在我們的 github 提交 PR 或者 issue 來(lái)幫助我們改進(jìn):
    https://github.com/loomnetwork/cryptozombie-lessons

    或者,如果你有任何的想法、建議甚至僅僅想和我們打聲招呼,歡迎來(lái)我們的電報(bào)群:
     https://t.me/loomnetworkcn
  */
}

特別是,最好為你合約中每個(gè)方法添加注釋來(lái)解釋它的預(yù)期行為。這樣其他開(kāi)發(fā)者(或者你自己,在6個(gè)月以后再回到這個(gè)項(xiàng)目中)可以很快地理解你的代碼而不需要逐行閱讀所有代碼。

Solidity 社區(qū)所使用的一個(gè)標(biāo)準(zhǔn)是使用一種被稱作 natspec 的格式,看起來(lái)像這樣:

/// @title 一個(gè)簡(jiǎn)單的基礎(chǔ)運(yùn)算合約
/// @author H4XF13LD MORRIS
/// @notice 現(xiàn)在,這個(gè)合約只添加一個(gè)乘法
contract Math {
  /// @notice 兩個(gè)數(shù)相乘
  /// @param x 第一個(gè) uint
  /// @param y  第二個(gè) uint
  /// @return z  (x * y) 的結(jié)果
  /// @dev 現(xiàn)在這個(gè)方法不檢查溢出
  function multiply(uint x, uint y) returns (uint z) {
    // 這只是個(gè)普通的注釋,不會(huì)被 natspec 解釋
    z = x * y;
  }
}

@title(標(biāo)題) 和 @author (作者)很直接了.

@notice (須知)向 用戶 解釋這個(gè)方法或者合約是做什么的。@dev (開(kāi)發(fā)者) 是向開(kāi)發(fā)者解釋更多的細(xì)節(jié)。

@param (參數(shù))和 @return (返回) 用來(lái)描述這個(gè)方法需要傳入什么參數(shù)以及返回什么值。

注意你并不需要每次都用上所有的標(biāo)簽,它們都是可選的。不過(guò)最少,寫(xiě)下一個(gè) @dev 注釋來(lái)解釋每個(gè)方法是做什么的。

實(shí)戰(zhàn)演練

ZombieOwnership 加上一些 natspec 標(biāo)簽:

zombieownership.sol

pragma solidity ^0.4.19;

import "./zombieattack.sol";
import "./erc721.sol";
import "./safemath.sol";

/// TODO: 把這里變成 natspec 標(biāo)準(zhǔn)的注釋把
/// @title 一個(gè)管理轉(zhuǎn)移僵尸所有權(quán)的合約
/// @author Corwien
/// @dev 符合 OpenZeppelin 對(duì) ERC721 標(biāo)準(zhǔn)草案的實(shí)現(xiàn)
/// @date 2018/06/17
contract ZombieOwnership is ZombieAttack, ERC721 {

  using SafeMath for uint256;

  mapping (uint => address) zombieApprovals;

  function balanceOf(address _owner) public view returns (uint256 _balance) {
    return ownerZombieCount[_owner];
  }

  function ownerOf(uint256 _tokenId) public view returns (address _owner) {
    return zombieToOwner[_tokenId];
  }

  function _transfer(address _from, address _to, uint256 _tokenId) private {
    ownerZombieCount[_to] = ownerZombieCount[_to].add(1);
    ownerZombieCount[msg.sender] = ownerZombieCount[msg.sender].sub(1);
    zombieToOwner[_tokenId] = _to;
    Transfer(_from, _to, _tokenId);
  }

  function transfer(address _to, uint256 _tokenId) public onlyOwnerOf(_tokenId) {
    _transfer(msg.sender, _to, _tokenId);
  }

  function approve(address _to, uint256 _tokenId) public onlyOwnerOf(_tokenId) {
    zombieApprovals[_tokenId] = _to;
    Approval(msg.sender, _to, _tokenId);
  }

  function takeOwnership(uint256 _tokenId) public {
    require(zombieApprovals[_tokenId] == msg.sender);
    address owner = ownerOf(_tokenId);
    _transfer(owner, msg.sender, _tokenId);
  }
}

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/24128.html

相關(guān)文章

  • 以太開(kāi)發(fā)實(shí)戰(zhàn)學(xué)習(xí)-solidity語(yǔ)法(二)

    摘要:以太坊開(kāi)發(fā)高級(jí)語(yǔ)言學(xué)習(xí)。地址以太坊區(qū)塊鏈由賬戶組成,你可以把它想象成銀行賬戶。使用很安全,因?yàn)樗哂幸蕴粎^(qū)塊鏈的安全保障除非竊取與以太坊地址相關(guān)聯(lián)的私鑰,否則是沒(méi)有辦法修改其他人的數(shù)據(jù)的。 以太坊開(kāi)發(fā)高級(jí)語(yǔ)言學(xué)習(xí)。 一、映射(Mapping)和地址(Address) 我們通過(guò)給數(shù)據(jù)庫(kù)中的僵尸指定主人, 來(lái)支持多玩家模式。 如此一來(lái),我們需要引入2個(gè)新的數(shù)據(jù)類型:mapping(映射)...

    wemall 評(píng)論0 收藏0
  • Java開(kāi)發(fā)區(qū)塊鏈的三大sdk庫(kù)

    摘要:是企業(yè)與區(qū)塊鏈相遇的地方。的框架旨在成為開(kāi)發(fā)區(qū)塊鏈解決方案的支柱。以太坊,主要是針對(duì)工程師使用進(jìn)行區(qū)塊鏈以太坊開(kāi)發(fā)的詳解。 如果你想將區(qū)塊鏈合并到一個(gè)Java項(xiàng)目中,現(xiàn)在我們來(lái)看看就是這個(gè)細(xì)分領(lǐng)域中三個(gè)最大的OSS玩家。 好的伙計(jì)們,我們都聽(tīng)說(shuō)過(guò)比特幣,以太坊或其他加密貨幣,其中有一些時(shí)髦的名字圍繞著我們常見(jiàn)的新聞,但我們作為Java開(kāi)發(fā)人員知道如何輕松地與這些區(qū)塊鏈技術(shù)進(jìn)行交互嗎?以...

    iKcamp 評(píng)論0 收藏0
  • 以太智能合約開(kāi)發(fā)第二篇:理解以太相關(guān)概念

    摘要:原文發(fā)表于以太坊智能合約開(kāi)發(fā)第二篇理解以太坊相關(guān)概念很多人都說(shuō)比特幣是區(qū)塊鏈,以太坊是區(qū)塊鏈。它是以太坊智能合約的運(yùn)行環(huán)境。是由以太坊節(jié)點(diǎn)提供。以太坊社區(qū)把基于智能合約的應(yīng)用稱為去中心化的應(yīng)用。 原文發(fā)表于:以太坊智能合約開(kāi)發(fā)第二篇:理解以太坊相關(guān)概念 很多人都說(shuō)比特幣是區(qū)塊鏈1.0,以太坊是區(qū)塊鏈2.0。在以太坊平臺(tái)上,可以開(kāi)發(fā)各種各樣的去中心化應(yīng)用,這些應(yīng)用構(gòu)成了以太坊的整個(gè)生態(tài)...

    yibinnn 評(píng)論0 收藏0
  • 如何使用密碼保護(hù)以太JSON-RPC的API?

    摘要:本文面向以太坊智能合約應(yīng)用程序開(kāi)發(fā)人員,并討論如何在密碼保護(hù)后,安全地運(yùn)行你的以太坊節(jié)點(diǎn),以便通過(guò)進(jìn)行安全輸出。以太坊,主要是針對(duì)工程師使用進(jìn)行區(qū)塊鏈以太坊開(kāi)發(fā)的詳解。 本文面向以太坊智能合約應(yīng)用程序開(kāi)發(fā)人員,并討論如何在密碼保護(hù)后,安全地運(yùn)行你的以太坊節(jié)點(diǎn),以便通過(guò)Internet進(jìn)行安全輸出。 Go Ethereum(geth)是以太坊節(jié)點(diǎn)最受歡迎的軟件。其他流行的以太坊實(shí)現(xiàn)是Pa...

    Zachary 評(píng)論0 收藏0
  • 如何使用密碼保護(hù)以太JSON-RPC的API?

    摘要:本文面向以太坊智能合約應(yīng)用程序開(kāi)發(fā)人員,并討論如何在密碼保護(hù)后,安全地運(yùn)行你的以太坊節(jié)點(diǎn),以便通過(guò)進(jìn)行安全輸出。以太坊,主要是針對(duì)工程師使用進(jìn)行區(qū)塊鏈以太坊開(kāi)發(fā)的詳解。 本文面向以太坊智能合約應(yīng)用程序開(kāi)發(fā)人員,并討論如何在密碼保護(hù)后,安全地運(yùn)行你的以太坊節(jié)點(diǎn),以便通過(guò)Internet進(jìn)行安全輸出。 Go Ethereum(geth)是以太坊節(jié)點(diǎn)最受歡迎的軟件。其他流行的以太坊實(shí)現(xiàn)是Pa...

    cartoon 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<