以太坊教程:搭建環境、編寫編譯一個智能合約
來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。本以太坊教程主要是介紹:搭建一個開發環境、編寫編譯一個智能合約。### 以太坊是什麼以太坊(Ethereum)是一個開源的有智能合約功能的公用區塊鏈平台。通過其專用加密貨幣以太幣(Ether)提供去中心化的虛擬機器(“以太虛擬機器” Ethereum Virtual Machine)來處理點對點合約。以太坊的概念首次在2013至2014年間由程式員Vitalik Buterin,受比特幣啟發後提出,大意為“下一代加密貨幣與去中心化應用平台”,在2014年通過ICO眾籌得以開始發展。目前以太幣是市值第二高的加密貨幣,僅次於比特幣。### 以太坊區塊鏈是什嗎?以太坊區塊鏈有 2 個主要組件:- 資料存放區:網路中每筆交易都儲存在區塊鏈上。當你部署合約時,就是一筆交易。當你執行合約功能時,也是另一筆交易。所有的這些交易都是公開的,每個人都可以看到並進行驗證。這個資料永遠也無法篡改。為了確保網路中的所有節點都有著同一份資料拷貝,並且沒有向區塊鏈中寫入任何的無效資料,以太坊使用一個叫做工作量證明的演算法來保證網路安全。- 代碼:就資料的層面而言,區塊鏈就是儲存體交易。在以太坊的世界裡,你可以通過一個叫 Solidity 的語言編寫邏輯/應用代碼(也就是智能合約)。然後用 solidity 編譯器將代碼編譯為以太坊位元組碼,並將位元組碼部署到區塊鏈上(也有一些其他的語言可以寫合約,不過 solidity 是到目前為止用得最多也是相對更容易的選擇)。所以,以太坊不僅僅會儲存體交易資料,它還會儲存和執行智能合約代碼。可以簡單的理解以太坊區塊鏈的作用就是儲存資料和代碼,並在 EVM(Ethereum Virtual Machine,以太坊虛擬機器)中執行代碼。### 要準備的基礎知識為了進行以太坊開發,你應該對以下語言/技術有基本瞭解:- 熟悉某種物件導向語言(如Python,Java,go)- HTML/CSS/Javascript- 基本的命令列互動如Linux shell命令- 理解資料庫的基本概念為了構建以太坊去中心化應用即Dapp(Decentralized application),以太坊有一個非常方便的 JavaScript 庫即 web3.js,你也可以在一些 js 架構中直接引入該庫構建應用,比如 react,angular,vue 等。### 樣本:一個以太坊投票應用[以太坊教程](http://xc.hubwiz.com/course/5a952991adb3847553d205d1)樣本中,我們將會構建一個簡單的去中心化投票應用。所謂去中心化應用,就是一個不只存在於某一中心化伺服器上的應用。在網路中成百上千的電腦上,會運行著非常多的應用副本,這使得它幾乎不可能出現宕機的情況。你將會構建一個投票應用,在這個應用中,你可以初始化參與選舉的候選者,並對候選者投票,而這些投票將會被記錄在區塊鏈上。你將會經曆編寫投票合約,部署到區塊鏈並與之互動的整個過程。你將會瞭解什麼是一個合約,將合約部署到區塊鏈上並與之互動意味著什麼。本質上,區塊鏈就像是一個分散式資料庫,這個資料庫維護了一個不斷增長的記錄鏈表。如果熟悉關係型資料庫,你應該知道一張表裡有很多行的資料。現在,對資料進行批(batch)量處理(比如每批 100 行),並將每個處理的批次相連。就可以形成一個區塊鏈了!在區塊鏈裡,每個批次的資料就叫一個塊(block),塊裡的每一行就叫一筆交易(transaction)。現在,你對以太坊已經有了基本瞭解,我們可以開始構建投票的 dapp 了。這將會加強你對以太坊的認識,並且初略瞭解以太坊的功能。### 以太坊開發環境搭建#### Linux樣本是 Ubuntu 16.04 下的學習環境搭建,你只需要成功安裝了 nodejs 和 npm,就可以繼續項目的下一步了。我們通過 npm 安裝 ganache 和 web3 包來為[以太坊教程](http://xc.hubwiz.com/course/5a952991adb3847553d205d1)提供支撐。我們也需要安裝 solc來編譯合約。下面是安裝過程:```$ sudo apt-get update$ curl -sL https://deb.nodesource.com/setup_7.x -o nodesource_setup.sh$ sudo bash nodesource_setup.sh$ sudo apt-get install nodejs$ node --versionv7.4.0$ npm --version4.0.5$ mkdir -p ethereum_voting_dapp/chapter1$ cd ethereum_voting_dapp/chapter1$ npm install ganache-cli web3@0.20.1 solc$ node_modules/.bin/ganache-cli```如果安裝成功,運行命令node_modules/.bin/ganache-cli,應該能夠看到下面的輸出。```Ganache CLI v6.0.3 (ganache-core: 2.0.2)Available Accounts==================(0) 0x5c252a0c0475f9711b56ab160a1999729eccce97(1) 0x353d310bed379b2d1df3b727645e200997016ba3(2) 0xa3ddc09b5e49d654a43e161cae3f865261cabd23(3) 0xa8a188c6d97ec8cf905cc1dd1cd318e887249ec5(4) 0xc0aa5f8b79db71335dacc7cd116f357d7ecd2798(5) 0xda695959ff85f0581ca924e549567390a0034058(6) 0xd4ee63452555a87048dcfe2a039208d113323790(7) 0xc60c8a7b752d38e35e0359e25a2e0f6692b10d14(8) 0xba7ec95286334e8634e89760fab8d2ec1226bf42(9) 0x208e02303fe29be3698732e92ca32b88d80a2d36Private Keys==================(0) a6de9563d3db157ed9926a993559dc177be74a23fd88ff5776ff0505d21fed2b(1) 17f71d31360fbafbc90cad906723430e9694daed3c24e1e9e186b4e3ccf4d603(2) ad2b90ce116945c11eaf081f60976d5d1d52f721e659887fcebce5c81ee6ce99(3) 68e2288df55cbc3a13a2953508c8e0457e1e71cd8ae62f0c78c3a5c929f35430(4) 9753b05bd606e2ffc65a190420524f2efc8b16edb8489e734a607f589f0b67a8(5) 6e8e8c468cf75fd4de0406a1a32819036b9fa64163e8be5bb6f7914ac71251cc(6) c287c82e2040d271b9a4e071190715d40c0b861eb248d5a671874f3ca6d978a9(7) cec41ef9ccf6cb3007c759bf3fce8ca485239af1092065aa52b703fd04803c9d(8) c890580206f0bbea67542246d09ab4bef7eeaa22c3448dcb7253ac2414a5362a(9) eb8841a5ae34ff3f4248586e73fcb274a7f5dd2dc07b352d2c4b71132b3c73f0HD Wallet==================Mnemonic: cancel better shock lady capable main crunch alcohol derive alarm duck umbrellaBase HD Path: m/44'/60'/0'/0/{account_index}Listening on localhost:8545```為了便於測試,ganache 預設會建立 10 個賬戶,每個賬戶有 100 個以太。如果你還不懂什麼是賬戶,把它想象成存錢的銀行賬戶就可以了(以太(Ether,ETH)就是以太坊生態系統中的 錢/貨幣)。你需要用這個賬戶建立交易,發送/接收以太。#### MacOS如果你還沒有安裝 homebrew,請按照 https://brew.sh/ 的指示安裝 homebrew。homebrew 是一個包管理器,它可以協助我們安裝開發所需的所有其他軟體。按照下面的指示安裝所有其他所需的包。```$ brew update$ brew install nodejs$ node --versionv7.10.0$ npm --version4.2.0$ mkdir -p ethereum_voting_dapp/chapter1$ cd ethereum_voting_dapp/chapter1$ npm install ganache-cli web3@0.20.1 solc$ node_modules/.bin/ganache-cli```我們通過 npm 安裝 ganache 和 web3 包。我們也需要安裝 solc 來編譯合約。如果安裝成功,運行命令node_modules/.bin/ganache-cli,應該能夠看到右圖所示的輸出。```Ganache CLI v6.0.3 (ganache-core: 2.0.2)Available Accounts==================(0) 0x5c252a0c0475f9711b56ab160a1999729eccce97(1) 0x353d310bed379b2d1df3b727645e200997016ba3(2) 0xa3ddc09b5e49d654a43e161cae3f865261cabd23(3) 0xa8a188c6d97ec8cf905cc1dd1cd318e887249ec5(4) 0xc0aa5f8b79db71335dacc7cd116f357d7ecd2798(5) 0xda695959ff85f0581ca924e549567390a0034058(6) 0xd4ee63452555a87048dcfe2a039208d113323790(7) 0xc60c8a7b752d38e35e0359e25a2e0f6692b10d14(8) 0xba7ec95286334e8634e89760fab8d2ec1226bf42(9) 0x208e02303fe29be3698732e92ca32b88d80a2d36Private Keys==================(0) a6de9563d3db157ed9926a993559dc177be74a23fd88ff5776ff0505d21fed2b(1) 17f71d31360fbafbc90cad906723430e9694daed3c24e1e9e186b4e3ccf4d603(2) ad2b90ce116945c11eaf081f60976d5d1d52f721e659887fcebce5c81ee6ce99(3) 68e2288df55cbc3a13a2953508c8e0457e1e71cd8ae62f0c78c3a5c929f35430(4) 9753b05bd606e2ffc65a190420524f2efc8b16edb8489e734a607f589f0b67a8(5) 6e8e8c468cf75fd4de0406a1a32819036b9fa64163e8be5bb6f7914ac71251cc(6) c287c82e2040d271b9a4e071190715d40c0b861eb248d5a671874f3ca6d978a9(7) cec41ef9ccf6cb3007c759bf3fce8ca485239af1092065aa52b703fd04803c9d(8) c890580206f0bbea67542246d09ab4bef7eeaa22c3448dcb7253ac2414a5362a(9) eb8841a5ae34ff3f4248586e73fcb274a7f5dd2dc07b352d2c4b71132b3c73f0HD Wallet==================Mnemonic: cancel better shock lady capable main crunch alcohol derive alarm duck umbrellaBase HD Path: m/44'/60'/0'/0/{account_index}Listening on localhost:8545```為了便於測試,ganache 預設會建立 10 個賬戶,每個賬戶有 100 個以太。如果你還不懂什麼是以太坊賬戶,把它想象成存錢的銀行賬戶就可以了(以太(Ether, ETH)就是以太坊生態系統中的錢/貨幣)。你需要用這個賬戶建立交易,發送/接收以太。#### Windows- 安裝 Visual Studio Community Edition。如果你選擇定製安裝,那麼至少應該安裝 Visual C++(目前的版本是 VS 2017)- 安裝 Windows SDK for Windows- 安裝 Python 2.7 如果你還沒有安裝的話,並且確保將它加入到環境變數 PATH- 安裝 git 如果你還沒有安裝並加入到 PATH - 安裝 OpenSSL。確保選擇了正確的安裝包,並且只安裝完整版(而不是輕裝版)。你必須將 OpenSSL 安裝到推薦安裝的位置 -- 不要改變安裝路徑- 下載和安裝 node v8.1.2 。不推薦使用版本 v6.11.0 搭配 VS2017- 執行命令 npm install ganache-cli web3@0.20.1 solc### Solidity Contracts現在已經安裝好 ganache 並運行,我們將會開始編寫第一個以太坊智能合約。我們會使用 solidity 程式設計語言來編寫合約。如果你熟悉物件導向編程,學慣用 solidity 寫合約應該非常簡單。我們會寫一個叫做 Voting 的合約(可以把合約看成是面對對象程式設計語言的一個類),這個合約有以下內容:- 一個建構函式,用來初始化一些候選者。- 一個用來投票的方法(對投票數加 1)- 一個返回候選者所獲得的總票數的方法當你把合約部署到區塊鏈的時候,就會調用建構函式,並只調用一次。與 web 世界裡每次部署代碼都會覆蓋舊代碼不同,在區塊鏈上部署的合約是不可改變的,也就是說,如果你更新合約並再次部署,舊的合約仍然會在區塊鏈上存在,並且資料仍在。新的部署將會建立合約的一個新的執行個體。```pragma solidity ^0.4.18;contract Voting { mapping (bytes32 => uint8) public votesReceived; bytes32[] public candidateList; function Voting(bytes32[] candidateNames) public { candidateList = candidateNames; } function totalVotesFor(bytes32 candidate) view public returns (uint8) { require(validCandidate(candidate)); return votesReceived[candidate]; } function voteForCandidate(bytes32 candidate) public { require(validCandidate(candidate)); votesReceived[candidate] += 1; } function validCandidate(bytes32 candidate) view public returns (bool) { for(uint i = 0; i < candidateList.length; i++) { if (candidateList[i] == candidate) { return true; } } return false; }}```將右側代碼拷貝到一個叫做 Voting.sol 的檔案中,並儲存到 chapter1 目錄下面。**代碼和解釋**- Line 1. 我們必須指定代碼將會哪個版本的編譯器進行編譯- Line 3. mapping 相當於一個關聯陣列或者是字典,是一個索引值對。mapping votesReceived 的鍵是候選者的名字,類型為 bytes32。mapping 的值是一個未賦值的整型,儲存的是投票數。- Line 4. 在很多程式設計語言中,僅僅通過 votesReceived.keys 就可以擷取所有的候選者姓名。但是,但是在 solidity 中沒有這樣的方法,所以我們必須單獨管理一個候選者數組 candidateList。- Line 14. 注意到 votesReceived[key] 有一個預設值 0,所以你不需要將其初始化為 0,直接加1 即可。你也會注意到每個函數有個可見度說明符(visibility specifier)(比如本例中的 public)。這意味著,函數可以從合約外調用。如果你不想要其他任何人調用這個函數,你可以把它設定為私人(private)函數。如果你不指定可見度,編譯器會拋出一個警告。最近 solidity 編譯器進行了一些改進,如果使用者忘記了對私人函數進行標記導致了外部可以調用私人函數,編譯器會捕獲這個問題。 [這裡](http://solidity.readthedocs.io/en/develop/miscellaneous.html#function-visibility-specifiers) 可以看到所有的可見度說明符。你也會在一些函數上看到一個修飾符 view。它通常用來告訴編譯器函數是唯讀(也就是說,調用該函數,區塊鏈狀態並不會更新)。所有的修飾符都可以在 [這裡](http://solidity.readthedocs.io/en/develop/miscellaneous.html#modifiers) 看到。### 編譯智能合約我們將會使用上一節安裝的 solc 庫來編譯代碼。如果你還記得的話,之前我們提到過 web3js 是一個庫,它能夠讓你通過 RPC 與區塊鏈進行互動。我們將會在 node 控制台裡用這個庫部署合約,並與區塊鏈進行互動。首先,在終端中運行 node 進入 node 控制台,初始化 web3 對象,並向區塊鏈查詢擷取所有的賬戶。>確保與此同時 ganache 已經在另一個視窗中運行為了編譯合約,先從 Voting.sol 中載入代碼並綁定到一個 string 類型的變數,然後像下邊這樣對合約進行編譯。```$ nodeIn the node console> Web3 = require('web3')> web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));> web3.eth.accounts['0x5c252a0c0475f9711b56ab160a1999729eccce97''0x353d310bed379b2d1df3b727645e200997016ba3''0xa3ddc09b5e49d654a43e161cae3f865261cabd23''0xa8a188c6d97ec8cf905cc1dd1cd318e887249ec5''0xc0aa5f8b79db71335dacc7cd116f357d7ecd2798''0xda695959ff85f0581ca924e549567390a0034058''0xd4ee63452555a87048dcfe2a039208d113323790''0xc60c8a7b752d38e35e0359e25a2e0f6692b10d14''0xba7ec95286334e8634e89760fab8d2ec1226bf42''0x208e02303fe29be3698732e92ca32b88d80a2d36']> code = fs.readFileSync('Voting.sol').toString()> solc = require('solc')> compiledCode = solc.compile(code)```當你成功地編譯好合約,列印 compiledCode 對象(直接在 node 控制台輸入 compiledCode 就可以看到內容),你會注意到有兩個重要的欄位,它們很重要,你必須要理解:- 1.compiledCode.contracts[':Voting'].bytecode: 這就是 Voting.sol 編譯好後的位元組碼。也是要部署到區塊鏈上的代碼。- 2.compiledCode.contracts[':Voting'].interface: 這是一個合約的介面或者說模板(叫做 abi 定義),它告訴了使用者在這個合約裡有哪些方法。在未來無論何時你想要跟任意一個合約進行互動,你都會需要這個 abi 定義。你可以在這裡 看到 [ABI](https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI) 的更多內容。教程參考匯智網的DAPP開發入門教程,如果大家等不及部落格更新,也可以直接存取這個[以太坊教程](http://xc.hubwiz.com/course/5a952991adb3847553d205d1)。252 次點擊