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

資訊專欄INFORMATION COLUMN

以太坊開發(fā)實(shí)戰(zhàn)學(xué)習(xí)-Solidity初學(xué)(一)

googollee / 2574人閱讀

摘要:可以把賬戶視為銀行賬戶,以太幣就是以太坊生態(tài)系統(tǒng)中的貨幣。重點(diǎn)合約狀態(tài)是持久化到區(qū)塊鏈上的,因此對(duì)合約狀態(tài)的修改需要消耗以太幣。也就是說(shuō)它們被寫入以太幣區(qū)塊鏈中想象成寫入一個(gè)數(shù)據(jù)庫(kù)。注中,實(shí)際上是代名詞,一個(gè)位的無(wú)符號(hào)整數(shù)。建立一個(gè)命名為。

區(qū)塊鏈火熱,作為程序猿的我,當(dāng)然也不能袖手旁觀,一位資深技術(shù)開發(fā)朋友曾笑說(shuō):這是屌絲程序猿改變命運(yùn)為數(shù)不多的機(jī)會(huì)之一。所以,從今天開始,就要步入?yún)^(qū)塊鏈的開發(fā)大潮中。
一、合約開發(fā)流程

語(yǔ)言:使用 node.js 開發(fā)該項(xiàng)目
大概流程:

合約代碼編寫(Solidity)-> 合約編譯(solc)-> 合約部署(web3)

開發(fā)語(yǔ)言及工具:

區(qū)塊鏈節(jié)點(diǎn):ganache-cli

基礎(chǔ)環(huán)境:node

合約開發(fā)語(yǔ)言:Solidity

合約編譯器:solc

合約訪問庫(kù):web3.js

二、基礎(chǔ)環(huán)境安裝

1、安裝 node.js

2、安裝 ganache-cli

sudo npm install -g ganache-cli

運(yùn)行:

ganache-cli

輸出:

?  ~ ganache-cli
Ganache CLI v6.1.0 (ganache-core: 2.1.0)

Available Accounts
==================
(0) 0x2c0e940b0732a3b49cb7dccc26e14cb4801dd1c3
(1) 0x65afabcf1fdb19ef88f8433af90136de56e7e412
(2) 0x65111c1fa94e15e8e3bdedb466004f67d6b46bab
(3) 0xfa44030a4216193d19a811267528e86cf1851e48
(4) 0xc29473dca76a2ebbb8b1badf6a8093c11b56ea84
(5) 0x06e55addeef67a46015e2790be1ada1deb3c9c70
(6) 0xc1ec7f3d08692d0bdd70d6ab3d5701f22f53a521
(7) 0x42e52cbb5e226ef8c2c9bf54737b87ccf94ebb08
(8) 0x8cebfdb948266022d2499118b0989b290d146d4c
(9) 0x17b791127c57dff3eb31cc203e404536ef7e0ba7

Private Keys
==================
(0) 3bb508f1c2c35083f7d69466830067c6582e4464ba61daffc947bb1aa98618e9
(1) fc06e722c10cd80b1b5b43355f81363dcbe6dcc8d3c59387f69c68ce99f36c53
(2) 07f37ed746ba88da289eaa780d6155d9fee456106d85169ad92a526c22192695
(3) 2619b581c083d20ff84db2688f4a9d836206ee37e993bc8cb1e089ad68c8673f
(4) c3f61de226b5d5c06cb941f93a2a3ec321dabc53a8fb68bee64d3aed5bc130e6
(5) f86e7b7e7a9cf7532004694cb22997ac521567b7c8e480dbee23e426ed787234
(6) 2035f13d8d64109f21e4eb32970e5934cddcd27bc55439634f49d4479c7abe77
(7) 3395049c4f8749b17e154c47199fa42ce538ed051b6240afc55f49d30406a4f0
(8) 976f56be1b1cd9f5c420a3fdb71eb3a8c3875a7bd3fba20c342389ba97b0a165
(9) a2a7a190ee76cdb0675b8af773fba55187ff4a0fc6c1e1021e717d19e0d591ee

HD Wallet
==================
Mnemonic:      result casino this poverty sleep joy toy sort onion spider bind evolve
Base HD Path:  m/44"/60"/0"/0/{account_index}

Listening on localhost:8545

ganache 默認(rèn)會(huì)自動(dòng)創(chuàng)建 10 個(gè)賬戶,每個(gè)賬戶有 100 個(gè)以太幣(ETH:Ether)。 可以把賬戶視為銀行賬戶,以太幣就是以太坊生態(tài)系統(tǒng)中的貨幣。

面輸出的最后一句話,描述了節(jié)點(diǎn)仿真器的監(jiān)聽地址和端口為localhost:8545,在使用 web3.js 時(shí),需要傳入這個(gè)地址來(lái)告訴web3js庫(kù)應(yīng)當(dāng)連接到哪一個(gè)節(jié)點(diǎn)。

三、合約設(shè)計(jì)

我們使用 Solidity 語(yǔ)言來(lái)編寫合約。如果你熟悉面向?qū)ο蟮拈_發(fā)和JavaScript,那么學(xué)習(xí)Solidity 應(yīng)該非常簡(jiǎn)單??梢詫⒑霞s類比于OOP的類:合約中的屬性用來(lái)聲明合約的狀態(tài),而合約中的方法則提供修改狀態(tài)的訪問接口。

重點(diǎn):

合約狀態(tài)是持久化到區(qū)塊鏈上的,因此對(duì)合約狀態(tài)的修改需要消耗以太幣。

只有在合約部署到區(qū)塊鏈的時(shí)候,才會(huì)調(diào)用構(gòu)造函數(shù),并且只調(diào)用一次。

與 web 世界里每次部署代碼都會(huì)覆蓋舊代碼不同,在區(qū)塊鏈上部署的合約是不可改變的,也就是說(shuō),如果你更新 合約并再次部署,舊的合約仍然會(huì)在區(qū)塊鏈上存在,并且合約的狀態(tài)數(shù)據(jù)也依然存在。新的部署將會(huì)創(chuàng)建合約的一 個(gè)新的實(shí)例。

四、合約語(yǔ)法

從最基本的開始入手:

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

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

contract HelloWorld {

}
1、版本指令

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

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

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

contract.sol 合約文件

// 1. 這里寫版本指令
pragma solidity ^0.4.19;

// 2. 這里建立智能合約
contract HelloWorld {

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

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

建立一個(gè)版本為 0.4.19,我們的合約基于這個(gè)版本的編譯器。

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

Contract.sol

pragma solidity ^0.4.19; // 1. 這里寫版本指令

// 2. 這里建立智能合約
contract ZombieFactory {

}
2、狀態(tài)變量和整數(shù)

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

示例:

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

在上面的例子中,定義 myUnsignedInteger 為 uint 類型,并賦值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, uint16, uint32, 等…… 但一般來(lái)講你愿意使用簡(jiǎn)單的 uint, 除非在某些特殊情況下,這我們后面會(huì)講。

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

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

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

Contract.sol

pragma solidity ^0.4.19; // 1. 這里寫版本指令

// 2. 這里建立智能合約
contract ZombieFactory {

  // 3.定義 dnaDigits 為 uint 數(shù)據(jù)類型, 并賦值 16
  uint dnaDigits = 16;
}
3、數(shù)學(xué)運(yùn)算

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

加法: x + y

減法: x - y,

乘法: x * y

除法: x / y

取模 / 求余: x % y (例如, 13 % 5 余 3, 因?yàn)?3除以5,余3)

Solidity 還支持 乘方操作 (如:x 的 y次方) // 例如: 5 ** 2 = 25

uint x = 5 ** 2; // equal to 5^2 = 25
實(shí)戰(zhàn)演練3

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

建立一個(gè)uint類型的變量,名字叫dnaModulus, 令其等于 10dnaDigits 次方。

Contract.sol

pragma solidity ^0.4.19; // 1. 這里寫版本指令

// 2. 這里建立智能合約
contract ZombieFactory {

  // 3. 定義 dnaDigits 為 uint 數(shù)據(jù)類型, 并賦值 16
  uint dnaDigits = 16;

  // 4. 10 的 dnaDigits 次方
  uint dnaModulus = 10 ** dnaDigits;
}
4、結(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)演練4

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

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

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

Contract.sol

// 1. 這里寫版本指令
pragma solidity ^0.4.19; 

// 2. 這里建立智能合約
contract ZombieFactory {

  // 3. 定義 dnaDigits 為 uint 數(shù)據(jù)類型, 并賦值 16
  uint dnaDigits = 16;

  // 4. 10 的 dnaDigits 次方
  uint dnaModulus = 10 ** dnaDigits;

   // 5.結(jié)構(gòu)體定義
   struct Zombie {
        string name;
        uint dna;

    }
}
5、數(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ù)組 例如,上一節(jié)提到的 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)演練5

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

創(chuàng)建一個(gè)數(shù)據(jù)類型為 Zombie 的結(jié)構(gòu)體數(shù)組,用 public 修飾,命名為:zombies.

Contract.sol

// 1. 這里寫版本指令
pragma solidity ^0.4.19; 

// 2. 這里建立智能合約
contract ZombieFactory {

  // 3. 定義 dnaDigits 為 uint 數(shù)據(jù)類型, 并賦值 16
  uint dnaDigits = 16;

  // 4. 10 的 dnaDigits 次方
  uint dnaModulus = 10 ** dnaDigits;

   // 5.結(jié)構(gòu)體定義
   struct Zombie {
        string name;
        uint dna;

    }
    
    // 6.數(shù)組類型為結(jié)構(gòu)體的公共數(shù)組
    Zombie[] public zombies;
}
6、定義函數(shù)

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

function eatHamburgers(string _name, uint _amount) {

}

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

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

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

eatHamburgers("vitalik", 100);
實(shí)戰(zhàn)演練6

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

建立一個(gè)函數(shù) createZombie。 它有兩個(gè)參數(shù): _name (類型為string), 和 _dna (類型為uint)。

暫時(shí)讓函數(shù)空著——我們?cè)诤竺鏁?huì)增加內(nèi)容。
Contract.sol

// 1. 這里寫版本指令
pragma solidity ^0.4.19; 

// 2. 這里建立智能合約
contract ZombieFactory {

  // 3. 定義 dnaDigits 為 uint 數(shù)據(jù)類型, 并賦值 16
  uint dnaDigits = 16;

  // 4. 10 的 dnaDigits 次方
  uint dnaModulus = 10 ** dnaDigits;

   // 5.結(jié)構(gòu)體定義
   struct Zombie {
        string name;
        uint dna;

    }
    
    // 6.數(shù)組類型為結(jié)構(gòu)體的公共數(shù)組
    Zombie[] public zombies;
    
    // 7.創(chuàng)建函數(shù)
    function createZombie(string _name, uint _dna){
        
    }
}
7、使用結(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)演練7

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

1.在函數(shù)體里新創(chuàng)建一個(gè) Zombie, 然后把它加入 zombies 數(shù)組中。 新創(chuàng)建的僵尸的 namedna,來(lái)自于函數(shù)的參數(shù)。

2.讓我們用一行代碼簡(jiǎn)潔地完成它。

Contract.sol

// 1. 這里寫版本指令
pragma solidity ^0.4.19; 

// 2. 這里建立智能合約
contract ZombieFactory {

  // 3. 定義 dnaDigits 為 uint 數(shù)據(jù)類型, 并賦值 16
  uint dnaDigits = 16;

  // 4. 10 的 dnaDigits 次方
  uint dnaModulus = 10 ** dnaDigits;

   // 5.結(jié)構(gòu)體定義
   struct Zombie {
        string name;
        uint dna;

    }
    
    // 6.數(shù)組類型為結(jié)構(gòu)體的公共數(shù)組
    Zombie[] public zombies;
    
    // 7.創(chuàng)建函數(shù)
    function createZombie(string _name, uint _dna){
         // 8.使用結(jié)構(gòu)體和數(shù)組(初始化全局?jǐn)?shù)組)
        zombies.push(Zombie(_name, _dna));
    }
}
8、私有 / 公共函數(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)演練8

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

1.變 createZombie 為私有函數(shù),不要忘記遵守命名的規(guī)矩哦!

Contract.sol

// 1. 這里寫版本指令
pragma solidity ^0.4.19; 

// 2. 這里建立智能合約
contract ZombieFactory {

  // 3. 定義 dnaDigits 為 uint 數(shù)據(jù)類型, 并賦值 16
  uint dnaDigits = 16;

  // 4. 10 的 dnaDigits 次方
  uint dnaModulus = 10 ** dnaDigits;

   // 5.結(jié)構(gòu)體定義
   struct Zombie {
        string name;
        uint dna;

    }
    
    // 6.數(shù)組類型為結(jié)構(gòu)體的公共數(shù)組
    Zombie[] public zombies;
    
    /*
    // 7.創(chuàng)建函數(shù)
    function createZombie(string _name, uint _dna){
         // 8.使用結(jié)構(gòu)體和數(shù)組(初始化全局?jǐn)?shù)組)
        zombies.push(Zombie(_name, _dna));
    }
    */
    
     // 7.創(chuàng)建函數(shù)(改為私有方法)
    function _createZombie(string _name, uint _dna) private {
         // 8.使用結(jié)構(gòu)體和數(shù)組(初始化全局?jǐn)?shù)組)
        zombies.push(Zombie(_name, _dna));
    }
    
   
}
9、函數(shù)的更多屬性

本節(jié)中我們將學(xué)習(xí)函數(shù)的返回值和修飾符。

返回值

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

string greeting = "What"s up dog";

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

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

函數(shù)的修飾符view,returns

上面的函數(shù)實(shí)際上沒有改變 Solidity 里的狀態(tài),即,它沒有改變?nèi)魏沃祷蛘邔懭魏螙|西。
這種情況下我們可以把函數(shù)定義為 view, 意味著它只能讀取數(shù)據(jù)不能更改數(shù)據(jù):

function sayHello() public view returns (string) {}

Solidity 還支持 pure 函數(shù), 表明這個(gè)函數(shù)甚至都不訪問應(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)演練9

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

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

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

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

Contract.sol

// 1. 這里寫版本指令
pragma solidity ^0.4.19; 

// 2. 這里建立智能合約
contract ZombieFactory {

  // 3. 定義 dnaDigits 為 uint 數(shù)據(jù)類型, 并賦值 16
  uint dnaDigits = 16;

  // 4. 10 的 dnaDigits 次方
  uint dnaModulus = 10 ** dnaDigits;

   // 5.結(jié)構(gòu)體定義
   struct Zombie {
        string name;
        uint dna;

    }
    
    // 6.數(shù)組類型為結(jié)構(gòu)體的公共數(shù)組
    Zombie[] public zombies;
    
    /*
    // 7.創(chuàng)建函數(shù)
    function createZombie(string _name, uint _dna){
         // 8.使用結(jié)構(gòu)體和數(shù)組(初始化全局?jǐn)?shù)組)
        zombies.push(Zombie(_name, _dna));
    }
    */
    
     // 7.創(chuàng)建函數(shù)(改為私有方法)
    function _createZombie(string _name, uint _dna) private {
         // 8.使用結(jié)構(gòu)體和數(shù)組(初始化全局?jǐn)?shù)組)
        zombies.push(Zombie(_name, _dna));
    }
    
    // 9.函數(shù)修飾符 private, view, returns 返回值
    function _generateRandomDna(string _str) private view returns (uint){
        
      }
    
  
}
10、Keccak256 和 類型轉(zhuǎn)換 散列函數(shù) 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");

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

注: 在區(qū)塊鏈中安全地產(chǎn)生一個(gè)隨機(jī)數(shù)是一個(gè)很難的問題, 本例的方法不安全,但是在我們的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)演練10

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

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

2.我們只想讓我們的DNA的長(zhǎng)度為16位 (還記得 dnaModulus?)。所以第二行代碼應(yīng)該 return 上面計(jì)算的數(shù)值對(duì) dnaModulus 求余數(shù)(%)。

Contract.sol

// 1. 這里寫版本指令
pragma solidity ^0.4.19; 

// 2. 這里建立智能合約
contract ZombieFactory {

  // 3. 定義 dnaDigits 為 uint 數(shù)據(jù)類型, 并賦值 16
  uint dnaDigits = 16;

  // 4. 10 的 dnaDigits 次方
  uint dnaModulus = 10 ** dnaDigits;

   // 5.結(jié)構(gòu)體定義
   struct Zombie {
        string name;
        uint dna;

    }
    
    // 6.數(shù)組類型為結(jié)構(gòu)體的公共數(shù)組
    Zombie[] public zombies;
    
    /*
    // 7.創(chuàng)建函數(shù)
    function createZombie(string _name, uint _dna){
         // 8.使用結(jié)構(gòu)體和數(shù)組(初始化全局?jǐn)?shù)組)
        zombies.push(Zombie(_name, _dna));
    }
    */
    
     // 7.創(chuàng)建函數(shù)(改為私有方法)
    function _createZombie(string _name, uint _dna) private {
         // 8.使用結(jié)構(gòu)體和數(shù)組(初始化全局?jǐn)?shù)組)
        zombies.push(Zombie(_name, _dna));
    }
    
    // 9.函數(shù)修飾符 private, view, returns 返回值
    function _generateRandomDna(string _str) private view returns (uint){
        // 10.散列并取模
        uint rand = uint(keccak256(_str));  // 注意這里需要將string類型轉(zhuǎn)為uint類型
        return rand % dnaModulus;
    }
        
      }

}
11、綜合應(yīng)用

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

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

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

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

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

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

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

Contract.sol

// 1. 這里寫版本指令
pragma solidity ^0.4.19; 

// 2. 這里建立智能合約
contract ZombieFactory {

  // 3. 定義 dnaDigits 為 uint 數(shù)據(jù)類型, 并賦值 16
  uint dnaDigits = 16;

  // 4. 10 的 dnaDigits 次方
  uint dnaModulus = 10 ** dnaDigits;

   // 5.結(jié)構(gòu)體定義
   struct Zombie {
        string name;
        uint dna;

    }
    
    // 6.數(shù)組類型為結(jié)構(gòu)體的公共數(shù)組
    Zombie[] public zombies;
    
    /*
    // 7.創(chuàng)建函數(shù)
    function createZombie(string _name, uint _dna){
         // 8.使用結(jié)構(gòu)體和數(shù)組(初始化全局?jǐn)?shù)組)
        zombies.push(Zombie(_name, _dna));
    }
    */
    
     // 7.創(chuàng)建函數(shù)(改為私有方法)
    function _createZombie(string _name, uint _dna) private {
         // 8.使用結(jié)構(gòu)體和數(shù)組(初始化全局?jǐn)?shù)組)
        zombies.push(Zombie(_name, _dna));
    }
    
    // 9.函數(shù)修飾符 private, view, returns 返回值
    function _generateRandomDna(string _str) private view returns (uint){
        // 10.散列并取模
        uint rand = uint(keccak256(_str));  // 注意這里需要將string類型轉(zhuǎn)為uint類型
        return rand % dnaModulus;
    }
        
     
     // 11、事件
    function createRandomZombie(string _name) public {
        uint randDna = _generateRandomDna(_name);
        _createZombie(_name, randDna);
    }

}
12、事件

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

事件 是合約和區(qū)塊鏈通訊的一種機(jī)制。你的前端應(yīng)用“監(jiān)聽”某些事件,并做出反應(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)聽這個(gè)事件。JavaScript 實(shí)現(xiàn)如下:

YourContract.IntegersAdded(function(error, result) { 
  // 干些事
}
實(shí)戰(zhàn)演練12

我們想每當(dāng)一個(gè)僵尸創(chuàng)造出來(lái)時(shí),我們的前端都能監(jiān)聽到這個(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.需要定義僵尸idarray.push() 返回數(shù)組的長(zhǎng)度類型是uint - 因?yàn)閿?shù)組的第一個(gè)元素的索引是 0, array.push() - 1 將是我們加入的僵尸的索引。 zombies.push() - 1 就是 id,數(shù)據(jù)類型是 uint。在下一行中你可以把它用到 NewZombie 事件中。

Contract.sol

// 1. 這里寫版本指令
pragma solidity ^0.4.19; 

// 2. 這里建立智能合約
contract ZombieFactory {

  // 12.這里建立事件
  event NewZombie(uint zombieId, string name, uint dna);

  // 3. 定義 dnaDigits 為 uint 數(shù)據(jù)類型, 并賦值 16
  uint dnaDigits = 16;

  // 4. 10 的 dnaDigits 次方
  uint dnaModulus = 10 ** dnaDigits;

   // 5.結(jié)構(gòu)體定義
   struct Zombie {
        string name;
        uint dna;

    }
    
    // 6.數(shù)組類型為結(jié)構(gòu)體的公共數(shù)組
    Zombie[] public zombies;
    
    /*
    // 7.創(chuàng)建函數(shù)
    function createZombie(string _name, uint _dna){
         // 8.使用結(jié)構(gòu)體和數(shù)組(初始化全局?jǐn)?shù)組)
        zombies.push(Zombie(_name, _dna));
    }
    */
    
     // 7.創(chuàng)建函數(shù)(改為私有方法)
    function _createZombie(string _name, uint _dna) private {
         // 8.使用結(jié)構(gòu)體和數(shù)組(初始化全局?jǐn)?shù)組)
         // zombies.push(Zombie(_name, _dna));
         
        // 12、數(shù)組長(zhǎng)度減一就是當(dāng)前的數(shù)組ID
        uint id = zombies.push(Zombie(_name, _dna)) - 1;

        // 12、這里觸發(fā)事件
        NewZombie(id, _name, _dna);
    }
    
    // 9.函數(shù)修飾符 private, view, returns 返回值
    function _generateRandomDna(string _str) private view returns (uint){
        // 10.散列并取模
        uint rand = uint(keccak256(_str));  // 注意這里需要將string類型轉(zhuǎn)為uint類型
        return rand % dnaModulus;
    }
        
     
     // 11、綜合函數(shù)
    function createRandomZombie(string _name) public {
        uint randDna = _generateRandomDna(_name);
        _createZombie(_name, randDna);
    }

}
五、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)在我們通過一段代碼來(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` 能訪問公共的函數(shù)以及事件

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

// 監(jiān)聽 `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
    // 通過這樣計(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過濾器。在后面的課程中,你可以看到全部的代碼。

六、Truffle框架學(xué)習(xí)

Truffle 是一個(gè)DApp開發(fā)框架,它簡(jiǎn)化了去中心化應(yīng)用的構(gòu)建和管理。


注:本教程是匯智網(wǎng)-以太坊DApp開發(fā)入門學(xué)習(xí)筆記,感興趣的同學(xué)可以去學(xué)習(xí)。

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

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

相關(guān)文章

  • 區(qū)塊鏈開發(fā)中使用的最流行的編程語(yǔ)言

    摘要:我們目前正處于一個(gè)新興的區(qū)塊鏈開發(fā)行業(yè)中。,一種在以太坊開發(fā)人員中流行的新的簡(jiǎn)單編程語(yǔ)言,因?yàn)樗怯糜陂_發(fā)以太坊智能合約的語(yǔ)言。它是全球至少萬(wàn)開發(fā)人員使用的世界上最流行的編程語(yǔ)言之一。以太坊,主要是針對(duì)工程師使用進(jìn)行區(qū)塊鏈以太坊開發(fā)的詳解。 我們目前正處于一個(gè)新興的區(qū)塊鏈開發(fā)行業(yè)中。區(qū)塊鏈技術(shù)處于初期階段,然而這種顛覆性技術(shù)已經(jīng)成功地風(fēng)靡全球,并且最近經(jīng)歷了一場(chǎng)與眾不同的繁榮。由于許多...

    2shou 評(píng)論0 收藏0
  • 工廠模式管理多個(gè)以太solidity智能合約

    摘要:在新智能合約的構(gòu)造函數(shù)中,將引用我們的合約工廠的地址。以太坊,主要是針對(duì)工程師使用進(jìn)行區(qū)塊鏈以太坊開發(fā)的詳解。以太坊入門教程,主要介紹智能合約與應(yīng)用開發(fā),適合入門。這里是原文用工廠模式管理多個(gè)智能合約 我們寫了一份小的計(jì)算合約作為Hello World。如果我們可以創(chuàng)建一個(gè)允許用戶創(chuàng)建自己的計(jì)數(shù)器的合約怎么辦? showImg(https://segmentfault.com/img/...

    leone 評(píng)論0 收藏0
  • solidity語(yǔ)言開發(fā)智能合約中的繼承

    摘要:你首先編寫基本智能合約并告知你的新智能合約將從基礎(chǔ)合約繼承。這些函數(shù)和狀態(tài)變量只能在內(nèi)部訪問即從當(dāng)前合約或從中派生的合約中,而其他情況不使用它。私有函數(shù)和狀態(tài)變量?jī)H對(duì)定義它們的智能合約可見,而不是在派生合約中可見。這里是原文語(yǔ)言開發(fā)中的繼承 我們已經(jīng)探索了很多主題,在編寫智能合約時(shí)我們發(fā)現(xiàn)經(jīng)常使用相同的模式:例如,智能合約具有在構(gòu)造函數(shù)中設(shè)置的所有者,然后生成修改器以便僅讓所有者使用一...

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

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

    yibinnn 評(píng)論0 收藏0
  • SegmentFault 技術(shù)周刊 Vol.41 - 深入學(xué)習(xí)區(qū)塊鏈

    摘要:和比特幣協(xié)議有所不同的是,以太坊的設(shè)計(jì)十分靈活,極具適應(yīng)性。超級(jí)賬本區(qū)塊鏈的商業(yè)應(yīng)用超級(jí)賬本超級(jí)賬本是基金會(huì)下的眾多項(xiàng)目中的一個(gè)。證書頒發(fā)機(jī)構(gòu)負(fù)責(zé)簽發(fā)撤 showImg(https://segmentfault.com/img/bV2ge9?w=900&h=385); 從比特幣開始 一個(gè)故事告訴你比特幣的原理及運(yùn)作機(jī)制 這篇文章的定位會(huì)比較科普,盡量用類比的方法將比特幣的基本原理講出來(lái)...

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

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

0條評(píng)論

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