以太坊Solidity開(kāi)發(fā)入門(基礎(chǔ)篇)

分享一個(gè)很有趣的以太坊開(kāi)發(fā)教程亭敢。從零開(kāi)始手把手教你以太坊開(kāi)發(fā)。

第1章: 課程概述

第一課你將創(chuàng)造一個(gè)"僵尸工廠", 用它建立一支僵尸部隊(duì)。

  • 我們的工廠會(huì)把我們部隊(duì)中所有的僵尸保存到數(shù)據(jù)庫(kù)中
  • 工廠會(huì)有一個(gè)函數(shù)能產(chǎn)生新的僵尸
  • 每個(gè)僵尸會(huì)有一個(gè)隨機(jī)的獨(dú)一無(wú)二的面孔
    在后面的課程里害碾,我們會(huì)增加功能。比如赦拘,讓僵尸能攻擊人類或其它僵尸! 但是在實(shí)現(xiàn)這些好玩的功能之前慌随,我們先要實(shí)現(xiàn)創(chuàng)建僵尸這樣的基本功能。

僵尸DNA如何運(yùn)作

僵尸的面孔取決于它的DNA。它的DNA很簡(jiǎn)單阁猜,由一個(gè)16位的整數(shù)組成:

8356281049284737

如同真正的DNA, 這個(gè)數(shù)字的不同部分會(huì)對(duì)應(yīng)不同的特點(diǎn)丸逸。 前2位代表頭型,緊接著的2位代表眼睛蹦漠,等等椭员。

注: 本教程我們盡量簡(jiǎn)化车海。我們的僵尸只有7種頭型(雖然2位數(shù)字允許100種可能性)笛园。以后我們會(huì)加入更多的頭型, 如果我們想讓僵尸有更多造型。

例如侍芝,前兩位數(shù)字是 83研铆, 計(jì)算僵尸的頭型,我們做83 % 7 + 1 = 7 運(yùn)算州叠, 此僵尸將被賦予第七類頭型棵红。

在右邊頁(yè)面,移動(dòng)頭基因head gene 滑塊到第七位置(圣誕帽)可見(jiàn)83所對(duì)應(yīng)的特點(diǎn)咧栗。

實(shí)戰(zhàn)演習(xí)

  • 玩一下頁(yè)面右側(cè)的滑塊逆甜。檢驗(yàn)一下不同的數(shù)字對(duì)應(yīng)不同的僵尸的長(zhǎng)相。

演示


第2章: 合約

從最基本的開(kāi)始入手:

Solidity 的代碼都包裹在合約里面. 一份合約就是以太應(yīng)幣應(yīng)用的基本模塊致板, 所有的變量和函數(shù)都屬于一份合約, 它是你所有應(yīng)用的起點(diǎn).

一份名為 HelloWorld 的空合約如下:

contract HelloWorld {

}

版本指令
所有的 Solidity 源碼都必須冠以 "version pragma" — 標(biāo)明 Solidity 編譯器的版本. 以避免將來(lái)新的編譯器可能破壞你的代碼交煞。

例如: pragma solidity ^0.4.19; (當(dāng)前 Solidity 的最新版本是 0.4.19).

綜上所述, 下面就是一個(gè)最基本的合約 — 每次建立一個(gè)新的項(xiàng)目時(shí)的第一段代碼:

pragma solidity ^0.4.19;

contract HelloWorld {

}

實(shí)戰(zhàn)演習(xí)

  • 為了建立我們的僵尸部隊(duì)斟或, 讓我們先建立一個(gè)基礎(chǔ)合約素征,稱為 ZombieFactory

  • 在右邊的輸入框里輸入 0.4.19萝挤,我們的合約基于這個(gè)版本的編譯器御毅。

  • 建立一個(gè)空合約ZombieFactory

pragma solidity ^0.4.19;

contract ZombieFactory {

}

第3章: 狀態(tài)變量和整數(shù)

真棒怜珍!我們已經(jīng)為我們的合約做了一個(gè)外殼端蛆, 下面學(xué)習(xí) Solidity 中如何使用變量。

狀態(tài)變量是被永久地保存在合約中酥泛。也就是說(shuō)它們被寫入以太幣區(qū)塊鏈中. 想象成寫入一個(gè)數(shù)據(jù)庫(kù)今豆。

例子:

contract Example {
  // 這個(gè)無(wú)符號(hào)整數(shù)將會(huì)永久的被保存在區(qū)塊鏈中
  uint myUnsignedInteger = 100;
}

在上面的例子中,定義 myUnsignedIntegeruint 類型揭璃,并賦值100晚凿。

無(wú)符號(hào)整數(shù): uint

uint 無(wú)符號(hào)數(shù)據(jù)類型, 指其值不能是負(fù)數(shù)瘦馍,對(duì)于有符號(hào)的整數(shù)存在名為 int 的數(shù)據(jù)類型歼秽。

注: Solidity中, uint 實(shí)際上是 uint256代名詞情组, 一個(gè)256位的無(wú)符號(hào)整數(shù)燥筷。你也可以定義位數(shù)少的uints — uint8箩祥, uint16uint32肆氓, 等…… 但一般來(lái)講你愿意使用簡(jiǎn)單的 uint袍祖, 除非在某些特殊情況下,這我們后面會(huì)講谢揪。

實(shí)戰(zhàn)演習(xí)

  • 我們的僵尸DNA將由一個(gè)十六位數(shù)字組成蕉陋。

  • 定義 dnaDigitsuint 數(shù)據(jù)類型, 并賦值 16

pragma solidity ^0.4.19;

contract ZombieFactory {
    uint dnaDigits = 16;
}

第4章: 數(shù)學(xué)運(yùn)算

在 Solidity 中拨扶,數(shù)學(xué)運(yùn)算很直觀明了凳鬓,與其它程序設(shè)計(jì)語(yǔ)言相同:

  • 加法: x + y
  • 減法: x - y,
  • 乘法: x * y
  • 除法: x / y
  • 取模 / 求余: x % y (例如, 13 % 53, 因?yàn)?3除以5,余3)
    Solidity 還支持 乘方操作 (如:x 的 y次方) // 例如: 5 ** 2 = 25
uint x = 5 ** 2; // equal to 5^2 = 25

實(shí)戰(zhàn)演習(xí)

為了保證我們的僵尸的DNA只含有16個(gè)字符患民,我們先造一個(gè)uint數(shù)據(jù)缩举,讓它等于10^16。這樣一來(lái)以后我們可以用模運(yùn)算符 % 把一個(gè)整數(shù)變成16位匹颤。

  • 建立一個(gè)uint類型的變量仅孩,名字叫dnaModulus, 令其等于 10 的 dnaDigits 次方.
pragma solidity ^0.4.19;

contract ZombieFactory {
    uint dnaDigits = 16;
    uint dnaModulus = 10 ** dnaDigits;
}

第5章: 結(jié)構(gòu)體

有時(shí)你需要更復(fù)雜的數(shù)據(jù)類型,Solidity 提供了 結(jié)構(gòu)體:

struct Person {
  uint age;
  string name;
}

結(jié)構(gòu)體允許你生成一個(gè)更復(fù)雜的數(shù)據(jù)類型印蓖,它有多個(gè)屬性辽慕。

注:我們剛剛引進(jìn)了一個(gè)新類型, string。 字符串用于保存任意長(zhǎng)度的 UTF-8 編碼數(shù)據(jù)另伍。 如: string greeting = "Hello world!"鼻百。

實(shí)戰(zhàn)演習(xí)

  • 在我們的程序中,我們將創(chuàng)建一些僵尸摆尝!每個(gè)僵尸將擁有多個(gè)屬性温艇,所以這是一個(gè)展示結(jié)構(gòu)體的完美例子。

  • 建立一個(gè)struct 命名為 Zombie.

  • 我們的 Zombie 結(jié)構(gòu)體有兩個(gè)屬性: name (類型為 string), 和 dna (類型為 uint)堕汞。

pragma solidity ^0.4.19;

contract ZombieFactory {

    uint dnaDigits = 16;
    uint dnaModulus = 10 ** dnaDigits;

    struct Zombie {
        string name;
        uint dna;
    }
}

第6章: 數(shù)組

如果你想建立一個(gè)集合勺爱,可以用 數(shù)組這樣的數(shù)據(jù)類型. Solidity 支持兩種數(shù)組: 靜態(tài) 數(shù)組和動(dòng)態(tài) 數(shù)組:

// 固定長(zhǎng)度為2的靜態(tài)數(shù)組:
uint[2] fixedArray;
// 固定長(zhǎng)度為5的string類型的靜態(tài)數(shù)組:
string[5] stringArray;
// 動(dòng)態(tài)數(shù)組,長(zhǎng)度不固定讯检,可以動(dòng)態(tài)添加元素:
uint[] dynamicArray;

你也可以建立一個(gè) 結(jié)構(gòu)體類型的數(shù)組 例如琐鲁,上一章提到的 Person:

Person[] people; // dynamic Array, we can keep adding to it

記住:狀態(tài)變量被永久保存在區(qū)塊鏈中人灼。所以在你的合約中創(chuàng)建動(dòng)態(tài)數(shù)組來(lái)保存成結(jié)構(gòu)的數(shù)據(jù)是非常有意義的围段。

公共數(shù)組

你可以定義 public 數(shù)組, Solidity 會(huì)自動(dòng)創(chuàng)建 getter 方法. 語(yǔ)法如下:

Person[] public people;

其它的合約可以從這個(gè)數(shù)組讀取數(shù)據(jù)(但不能寫入數(shù)據(jù)),所以這在合約中是一個(gè)有用的保存公共數(shù)據(jù)的模式投放。

實(shí)戰(zhàn)演習(xí)

為了把一個(gè)僵尸部隊(duì)保存在我們的APP里奈泪,并且能夠讓其它APP看到這些僵尸,我們需要一個(gè)公共數(shù)組。

  • 創(chuàng)建一個(gè)數(shù)據(jù)類型為 Zombie 的結(jié)構(gòu)體數(shù)組涝桅,用 public 修飾拜姿,命名為:zombies.
pragma solidity ^0.4.19;

contract ZombieFactory {

    uint dnaDigits = 16;
    uint dnaModulus = 10 ** dnaDigits;

    struct Zombie {
        uint dna;
        string name;
    }

    Zombie[] public zombies;

}

第7章: 定義函數(shù)

在 Solidity 中函數(shù)定義的句法如下:

function eatHamburgers(string _name, uint _amount) {

}

這是一個(gè)名為 eatHamburgers 的函數(shù),它接受兩個(gè)參數(shù):一個(gè) string類型的 和 一個(gè) uint類型的》胨欤現(xiàn)在函數(shù)內(nèi)部還是空的蕊肥。

注:習(xí)慣上函數(shù)里的變量都是以(_)開(kāi)頭 (但不是硬性規(guī)定) 以區(qū)別全局變量。我們整個(gè)教程都會(huì)沿用這個(gè)習(xí)慣蛤肌。

我們的函數(shù)定義如下:

eatHamburgers("vitalik", 100);

實(shí)戰(zhàn)演習(xí)

在我們的應(yīng)用里壁却,我們要能創(chuàng)建一些僵尸,讓我們寫一個(gè)函數(shù)做這件事吧寻定!

  • 建立一個(gè)函數(shù) createZombie儒洛。 它有兩個(gè)參數(shù): _name (類型為string), 和 _dna (類型為uint)。
    暫時(shí)讓函數(shù)空著——我們?cè)诤竺鏁?huì)增加內(nèi)容狼速。
pragma solidity ^0.4.19;

contract ZombieFactory {

    uint dnaDigits = 16;
    uint dnaModulus = 10 ** dnaDigits;

    struct Zombie {
        string name;
        uint dna;
    }

    Zombie[] public zombies;

    function createZombie(string _name, uint _dna) {
      
    }
}

第8章: 使用結(jié)構(gòu)體和數(shù)組

創(chuàng)建新的結(jié)構(gòu)體

還記得上個(gè)例子中的 Person 結(jié)構(gòu)嗎?

struct Person {
  uint age;
  string name;
}

Person[] public people;

現(xiàn)在我們學(xué)習(xí)創(chuàng)建新的 Person 結(jié)構(gòu)卦停,然后把它加入到名為 people 的數(shù)組中.

// 創(chuàng)建一個(gè)新的Person:
Person satoshi = Person(172, "Satoshi");

// 將新創(chuàng)建的satoshi添加進(jìn)people數(shù)組:
people.push(satoshi);

你也可以兩步并一步向胡,用一行代碼更簡(jiǎn)潔:

people.push(Person(16, "Vitalik"));

注:array.push() 在數(shù)組的 尾部 加入新元素 ,所以元素在數(shù)組中的順序就是我們添加的順序惊完, 如:

uint[] numbers;
numbers.push(5);
numbers.push(10);
numbers.push(15);
// numbers is now equal to [5, 10, 15]

實(shí)戰(zhàn)演習(xí)

讓我們創(chuàng)建名為createZombie的函數(shù)來(lái)做點(diǎn)兒什么吧僵芹。

  • 在函數(shù)體里新創(chuàng)建一個(gè) Zombie, 然后把它加入 zombies 數(shù)組中小槐。 新創(chuàng)建的僵尸的 namedna拇派,來(lái)自于函數(shù)的參數(shù)。
  • 讓我們用一行代碼簡(jiǎn)潔地完成它凿跳。
pragma solidity ^0.4.19;

contract ZombieFactory {

    uint dnaDigits = 16;
    uint dnaModulus = 10 ** dnaDigits;

    struct Zombie {
        string name;
        uint dna;
    }

    Zombie[] public zombies;

    function createZombie(string _name, uint _dna) {
        zombies.push(Zombie(_name, _dna));
    }

}


第9章: 私有 / 公共函數(shù)

Solidity 定義的函數(shù)的屬性默認(rèn)為公共件豌。 這就意味著任何一方 (或其它合約) 都可以調(diào)用你合約里的函數(shù)。

顯然控嗜,不是什么時(shí)候都需要這樣茧彤,而且這樣的合約易于受到攻擊。 所以將自己的函數(shù)定義為私有是一個(gè)好的編程習(xí)慣疆栏,只有當(dāng)你需要外部世界調(diào)用它時(shí)才將它設(shè)置為公共曾掂。
如何定義一個(gè)私有的函數(shù)呢?

uint[] numbers;

function _addToArray(uint _number) private {
  numbers.push(_number);
}

這意味著只有我們合約中的其它函數(shù)才能夠調(diào)用這個(gè)函數(shù)壁顶,給 numbers 數(shù)組添加新成員珠洗。

可以看到,在函數(shù)名字后面使用關(guān)鍵字 private 即可若专。和函數(shù)的參數(shù)類似许蓖,私有函數(shù)的名字用(_)起始。

實(shí)戰(zhàn)演習(xí)

我們合約的函數(shù) createZombie 的默認(rèn)屬性是公共的,這意味著任何一方都可以調(diào)用它去創(chuàng)建一個(gè)僵尸蛔糯。 咱們來(lái)把它變成私有吧拯腮!

  • createZombie 為私有函數(shù),不要忘記遵守命名的規(guī)矩哦蚁飒!
pragma solidity ^0.4.19;

contract ZombieFactory {

    uint dnaDigits = 16;
    uint dnaModulus = 10 ** dnaDigits;

    struct Zombie {
        string name;
        uint dna;
    }

    Zombie[] public zombies;

    function _createZombie(string _name, uint _dna) private {
        zombies.push(Zombie(_name, _dna));
    }

}

第10章: 函數(shù)的更多屬性

返回值

要想函數(shù)返回一個(gè)數(shù)值动壤,按如下定義:

string greeting = "What's up dog";

function sayHello() public returns (string) {
  return greeting;
}

Solidity 里,函數(shù)的定義里可包含返回值的數(shù)據(jù)類型(如本例中 string)淮逻。

函數(shù)的修飾符

上面的函數(shù)實(shí)際上沒(méi)有改變 Solidity 里的狀態(tài)琼懊,即,它沒(méi)有改變?nèi)魏沃祷蛘邔懭魏螙|西爬早。

這種情況下我們可以把函數(shù)定義為 view, 意味著它只能讀取數(shù)據(jù)不能更改數(shù)據(jù):

function _generateRandomDna(string _str)  private view returns(uint){

}

Solidity 還支持 pure函數(shù), 表明這個(gè)函數(shù)甚至都不訪問(wèn)應(yīng)用里的數(shù)據(jù)哼丈,例如:

function _multiply(uint a, uint b) private pure returns (uint) {
  return a * b;
}

這個(gè)函數(shù)甚至都不讀取應(yīng)用里的狀態(tài) — 它的返回值完全取決于它的輸入?yún)?shù),在這種情況下我們把函數(shù)定義為 pure.

注:可能很難記住何時(shí)把函數(shù)標(biāo)記為 pure/view筛严。 幸運(yùn)的是醉旦, Solidity 編輯器會(huì)給出提示,提醒你使用這些修飾符桨啃。

實(shí)戰(zhàn)演習(xí)

我們想建立一個(gè)幫助函數(shù)车胡,它根據(jù)一個(gè)字符串隨機(jī)生成一個(gè)DNA數(shù)據(jù)。

  • 創(chuàng)建一個(gè) private 函數(shù)照瘾,命名為 _generateRandomDna匈棘。它只接收一個(gè)輸入變量 _str (類型 string), 返回一個(gè) uint 類型的數(shù)值。

  • 此函數(shù)只讀取我們合約中的一些變量析命,所以標(biāo)記為view主卫。

  • 函數(shù)內(nèi)部暫時(shí)留空,以后我們?cè)偬砑哟a鹃愤。

pragma solidity ^0.4.19;

contract ZombieFactory {

    uint dnaDigits = 16;
    uint dnaModulus = 10 ** dnaDigits;

    struct Zombie {
        string name;
        uint dna;
    }

    Zombie[] public zombies;

    function _createZombie(string _name, uint _dna) private {
        zombies.push(Zombie(_name, _dna));
    }

    function _generateRandomDna(string _str) private view returns (uint) {
        
    }
}

第11章: Keccak256 和 類型轉(zhuǎn)換

Keccak256

如何讓 _generateRandomDna 函數(shù)返回一個(gè)全(半) 隨機(jī)的 uint?

Ethereum 內(nèi)部有一個(gè)散列函數(shù)keccak256簇搅,它用了SHA3版本。一個(gè)散列函數(shù)基本上就是把一個(gè)字符串轉(zhuǎn)換為一個(gè)256位的16進(jìn)制數(shù)字昼浦。字符串的一個(gè)微小變化會(huì)引起散列數(shù)據(jù)極大變化馍资。

這在 Ethereum 中有很多應(yīng)用,但是現(xiàn)在我們只是用它造一個(gè)偽隨機(jī)數(shù)关噪。

//6e91ec6b618bb462a4a6ee5aa2cb0e9cf30f7a052bb467b0ba58b8748c00d2e5
keccak256("aaaab");
//b1f078126895a1424524de5321b339ab00408010b7cf0e6ed451514981e58aa9
keccak256("aaaac");

顯而易見(jiàn)鸟蟹,輸入字符串只改變了一個(gè)字母,輸出就已經(jīng)天壤之別了使兔。

注: 在區(qū)塊鏈中安全地產(chǎn)生一個(gè)隨機(jī)數(shù)是一個(gè)很難的問(wèn)題建钥, 本例的方法不安全,但是在我們的Zombie DNA算法里不是那么重要虐沥,已經(jīng)很好地滿足我們的需要了熊经。

類型轉(zhuǎn)換

有時(shí)你需要變換數(shù)據(jù)類型泽艘。例如:

uint8 a = 5;
uint b = 6;
// 將會(huì)拋出錯(cuò)誤,因?yàn)?a * b 返回 uint, 而不是 uint8:
uint8 c = a * b;
// 我們需要將 b 轉(zhuǎn)換為 uint8:
uint8 c = a * uint8(b);

上面, a * b 返回類型是 uint, 但是當(dāng)我們嘗試用 uint8 類型接收時(shí), 就會(huì)造成潛在的錯(cuò)誤镐依。如果把它的數(shù)據(jù)類型轉(zhuǎn)換為 uint8, 就可以了匹涮,編譯器也不會(huì)出錯(cuò)。

實(shí)戰(zhàn)演習(xí)

  • _generateRandomDna 函數(shù)添加代碼! 它應(yīng)該完成如下功能:

    • 第一行代碼取 _strkeccak256 散列值生成一個(gè)偽隨機(jī)十六進(jìn)制數(shù)槐壳,類型轉(zhuǎn)換為 uint, 最后保存在類型為 uint 名為 rand 的變量中然低。

    • 第二行代碼應(yīng)該 return 上面計(jì)算的數(shù)值對(duì) dnaModulus 求余數(shù)(%)。

pragma solidity ^0.4.19;

contract ZombieFactory {

    uint dnaDigits = 16;
    uint dnaModulus = 10 ** dnaDigits;

    struct Zombie {
        string name;
        uint dna;
    }

    Zombie[] public zombies;

    function _createZombie(string _name, uint _dna) private {
        zombies.push(Zombie(_name, _dna));
    }

    function _generateRandomDna(string _str) private view returns (uint) {
        uint rand = uint(keccak256(_str));
        return rand % dnaModulus;
    }
}

第12章: 放在一起

我們就快完成我們的隨機(jī)僵尸制造器了务唐,來(lái)寫一個(gè)公共的函數(shù)把所有的部件連接起來(lái)雳攘。

寫一個(gè)公共函數(shù),它有一個(gè)參數(shù)枫笛,用來(lái)接收僵尸的名字吨灭,之后用它生成僵尸的DNA。

實(shí)戰(zhàn)演習(xí)

  • 創(chuàng)建一個(gè) public 函數(shù)刑巧,命名為createRandomZombie. 它將被傳入一個(gè)變量 _name (數(shù)據(jù)類型是 string)喧兄。 (注: 定義公共函數(shù) public 和定義一個(gè)私有 private 函數(shù)的做法一樣)。

  • 函數(shù)的第一行應(yīng)該調(diào)用 _generateRandomDna 函數(shù)海诲,傳入 _name 參數(shù), 結(jié)果保存在一個(gè)類型為 uint 的變量里繁莹,命名為 randDna

  • 第二行調(diào)用 _createZombie 函數(shù)特幔, 傳入?yún)?shù): _namerandDna

  • 整個(gè)函數(shù)應(yīng)該是4行代碼 (包括函數(shù)的結(jié)束符號(hào) })闸昨。

   pragma solidity ^0.4.19;

contract ZombieFactory {

    uint dnaDigits = 16;
    uint dnaModulus = 10 ** dnaDigits;

    struct Zombie {
        string name;
        uint dna;
    }

    Zombie[] public zombies;

    function _createZombie(string _name, uint _dna) private {
        zombies.push(Zombie(_name, _dna));
   
    }

    function _generateRandomDna(string _str) private view returns (uint) {
        uint rand = uint(keccak256(_str));
        return rand % dnaModulus;
    }

    function createRandomZombie(string _name) public {
        uint randDna = _generateRandomDna(_name);
        _createZombie(_name, randDna);
    }

}

第13章: 事件

我們的合約幾乎就要完成了蚯斯!讓我們加上一個(gè)事件.

事件 是合約和區(qū)塊鏈通訊的一種機(jī)制。你的前端應(yīng)用“監(jiān)聽(tīng)”某些事件饵较,并做出反應(yīng)拍嵌。

例子:

// 這里建立事件
event IntegersAdded(uint x, uint y, uint result);

function add(uint _x, uint _y) public {
  uint result = _x + _y;
  //觸發(fā)事件,通知app
  IntegersAdded(_x, _y, result);
  return result;
}

你的 app 前端可以監(jiān)聽(tīng)這個(gè)事件循诉。JavaScript 實(shí)現(xiàn)如下:

YourContract.IntegersAdded(function(error, result) { 
  // 干些事
}

實(shí)戰(zhàn)演習(xí)

我們想每當(dāng)一個(gè)僵尸創(chuàng)造出來(lái)時(shí)横辆,我們的前端都能監(jiān)聽(tīng)到這個(gè)事件,并將它顯示出來(lái)茄猫。

1狈蚤。 定義一個(gè) 事件 叫做 NewZombie。 它有3個(gè)參數(shù): zombieId (uint)划纽, name (string)脆侮, 和 dna (uint)

2勇劣。 修改 _createZombie 函數(shù)使得當(dāng)新僵尸造出來(lái)并加入zombies數(shù)組后靖避,生成事件NewZombie潭枣。

3。 需要定義僵尸id幻捏。 array.push() 返回?cái)?shù)組的長(zhǎng)度類型是uint - 因?yàn)閿?shù)組的第一個(gè)元素的索引是 0盆犁, array.push() - 1 將是我們加入的僵尸的索引。 zombies.push() - 1 就是 id篡九,數(shù)據(jù)類型是 uint谐岁。在下一行中你可以把它用到 NewZombie 事件中。

pragma solidity ^0.4.19;

contract ZombieFactory {

   event NewZombie (uint zombieId, string name, uint dna);

   uint dnaDigits = 16;
   uint dnaModulus = 10 ** dnaDigits;
   
   struct Zombie{
        string name;
        uint dna;
    }
    
    Zombie[] public zombies;
    
   function _createZombie(string _name, uint _dna) private {
       uint id = zombies.push(Zombie(_name, _dna)) - 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 {
        uint randDna = _generateRandomDna(_name);
        _createZombie(_name, randDna);
    }


}

第14章: Web3.js

我們的 Solidity 合約完工了瓮下! 現(xiàn)在我們要寫一段 JavaScript 前端代碼來(lái)調(diào)用這個(gè)合約翰铡。

以太坊有一個(gè) JavaScript 庫(kù),名為Web3.js讽坏。

在后面的課程里锭魔,我們會(huì)進(jìn)一步地教你如何安裝一個(gè)合約,如何設(shè)置Web3.js路呜。 但是現(xiàn)在我們通過(guò)一段代碼來(lái)了解 Web3.js 是如何和我們發(fā)布的合約交互的吧迷捧。

如果下面的代碼你不能全都理解,不用擔(dān)心胀葱。

// 下面是調(diào)用合約的方式:
var abi = /* abi是由編譯器生成的 */
var ZombieFactoryContract = web3.eth.contract(abi)
var contractAddress = /* 發(fā)布之后在以太坊上生成的合約地址 */
var ZombieFactory = ZombieFactoryContract.at(contractAddress)
// `ZombieFactory` 能訪問(wèn)公共的函數(shù)以及事件

// 某個(gè)監(jiān)聽(tīng)文本輸入的監(jiān)聽(tīng)器:
$("#ourButton").click(function(e) {
  var name = $("#nameInput").val()
  //調(diào)用合約的 `createRandomZombie` 函數(shù):
  ZombieFactory.createRandomZombie(name)
})

// 監(jiān)聽(tīng) `NewZombie` 事件, 并且更新UI
var event = ZombieFactory.NewZombie(function(error, result) {
  if (error) return
  generateZombie(result.zombieId, result.name, result.dna)
})

// 獲取 Zombie 的 dna, 更新圖像
function generateZombie(id, name, dna) {
  let dnaStr = String(dna)
  // 如果dna少于16位,在它前面用0補(bǔ)上
  while (dnaStr.length < 16)
    dnaStr = "0" + dnaStr

  let zombieDetails = {
    // 前兩位數(shù)構(gòu)成頭部.我們可能有7種頭部, 所以 % 7
    // 得到的數(shù)在0-6,再加上1,數(shù)的范圍變成1-7
    // 通過(guò)這樣計(jì)算:
    headChoice: dnaStr.substring(0, 2) % 7 + 1漠秋,
    // 我們得到的圖片名稱從head1.png 到 head7.png

    // 接下來(lái)的兩位數(shù)構(gòu)成眼睛, 眼睛變化就對(duì)11取模:
    eyeChoice: dnaStr.substring(2, 4) % 11 + 1,
    // 再接下來(lái)的兩位數(shù)構(gòu)成衣服,衣服變化就對(duì)6取模:
    shirtChoice: dnaStr.substring(4, 6) % 6 + 1,
    //最后6位控制顏色. 用css選擇器: hue-rotate來(lái)更新
    // 360度:
    skinColorChoice: parseInt(dnaStr.substring(6, 8) / 100 * 360),
    eyeColorChoice: parseInt(dnaStr.substring(8, 10) / 100 * 360),
    clothesColorChoice: parseInt(dnaStr.substring(10, 12) / 100 * 360),
    zombieName: name,
    zombieDescription: "A Level 1 CryptoZombie",
  }
  return zombieDetails
}

我們的 JavaScript 所做的就是獲取由zombieDetails 產(chǎn)生的數(shù)據(jù), 并且利用瀏覽器里的 JavaScript 神奇功能 (我們用 Vue.js)抵屿,置換出圖像以及使用CSS過(guò)濾器庆锦。在后面的課程中,你可以看到全部的代碼轧葛。
演示

下一篇:以太坊Solidity開(kāi)發(fā)入門(進(jìn)階篇)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末搂抒,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子尿扯,更是在濱河造成了極大的恐慌求晶,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,290評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件衷笋,死亡現(xiàn)場(chǎng)離奇詭異芳杏,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)辟宗,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門爵赵,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人慢蜓,你說(shuō)我怎么就攤上這事亚再。” “怎么了晨抡?”我有些...
    開(kāi)封第一講書人閱讀 156,872評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵氛悬,是天一觀的道長(zhǎng)则剃。 經(jīng)常有香客問(wèn)我,道長(zhǎng)如捅,這世上最難降的妖魔是什么棍现? 我笑而不...
    開(kāi)封第一講書人閱讀 56,415評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮镜遣,結(jié)果婚禮上己肮,老公的妹妹穿的比我還像新娘。我一直安慰自己悲关,他們只是感情好谎僻,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,453評(píng)論 6 385
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著寓辱,像睡著了一般艘绍。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上秫筏,一...
    開(kāi)封第一講書人閱讀 49,784評(píng)論 1 290
  • 那天诱鞠,我揣著相機(jī)與錄音,去河邊找鬼这敬。 笑死航夺,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的崔涂。 我是一名探鬼主播阳掐,決...
    沈念sama閱讀 38,927評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼冷蚂!你這毒婦竟也來(lái)了锚烦?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 37,691評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤帝雇,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后蛉拙,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體尸闸,經(jīng)...
    沈念sama閱讀 44,137評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,472評(píng)論 2 326
  • 正文 我和宋清朗相戀三年孕锄,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了吮廉。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,622評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡畸肆,死狀恐怖宦芦,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情轴脐,我是刑警寧澤调卑,帶...
    沈念sama閱讀 34,289評(píng)論 4 329
  • 正文 年R本政府宣布抡砂,位于F島的核電站,受9級(jí)特大地震影響恬涧,放射性物質(zhì)發(fā)生泄漏注益。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,887評(píng)論 3 312
  • 文/蒙蒙 一溯捆、第九天 我趴在偏房一處隱蔽的房頂上張望丑搔。 院中可真熱鬧,春花似錦提揍、人聲如沸啤月。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,741評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)谎仲。三九已至,卻和暖如春售碳,著一層夾襖步出監(jiān)牢的瞬間强重,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工贸人, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留间景,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,316評(píng)論 2 360
  • 正文 我出身青樓艺智,卻偏偏與公主長(zhǎng)得像倘要,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子十拣,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,490評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • 上一篇:以太坊Solidity開(kāi)發(fā)入門(進(jìn)階篇) 第1章: 智能協(xié)議的永固性 到現(xiàn)在為止封拧,我們講的 Solidit...
    那個(gè)大螺絲閱讀 4,019評(píng)論 0 8
  • 上一篇:以太坊Solidity開(kāi)發(fā)入門(基礎(chǔ)篇) 第1章: 第二課概覽 在第一課中,我們創(chuàng)建了一個(gè)函數(shù)用來(lái)生成僵尸...
    那個(gè)大螺絲閱讀 3,594評(píng)論 0 8
  • 好我與壞我夭问,二元對(duì)立無(wú)處不在泽西,意識(shí)和潛意識(shí)就是一個(gè)二元對(duì)立,如果A的一面達(dá)到了極致缰趋,-A的一面捧杉,也會(huì)達(dá)到極致。 夫...
    423429d90f38閱讀 226評(píng)論 0 0
  • 閑來(lái)無(wú)事終于看完了三體,拋開(kāi)科幻背景灰粮,我一直以為這是一部討論多個(gè)文明交集,以及面對(duì)高端文明的壓力下人類所表現(xiàn)出不同...
    Nurita閱讀 2,536評(píng)論 0 50
  • 如果你用別人能理解的語(yǔ)言與對(duì)方談話仔涩,那么談話會(huì)進(jìn)入對(duì)方的大腦。如果你用對(duì)方的語(yǔ)言與之談話粘舟,那么談話會(huì)進(jìn)入對(duì)方的心里...
    心中境地閱讀 95評(píng)論 0 0