1. 程式人生 > >以太坊教程:搭建環境、編寫編譯一個智能合約

以太坊教程:搭建環境、編寫編譯一個智能合約

以太坊教程 以太坊 以太坊開發 智能合約 區塊鏈 區塊鏈開發 solidity

本以太坊教程主要是介紹:搭建一個開發環境、編寫編譯一個智能合約。

以太坊是什麽

以太坊(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 等。

示例:一個以太坊投票應用

以太坊教程示例中,我們將會構建一個簡單的去中心化投票應用。所謂去中心化應用,就是一個不只存在於某一中心化服務器上的應用。在網絡中成百上千的電腦上,會運行著非常多的應用副本,這使得它幾乎不可能出現宕機的情況。你將會構建一個投票應用,在這個應用中,你可以初始化參與選舉的候選者,並對候選者投票,而這些投票將會被記錄在區塊鏈上。你將會經歷編寫投票合約,部署到區塊鏈並與之交互的整個過程。你將會了解什麽是一個合約,將合約部署到區塊鏈上並與之交互意味著什麽。

本質上,區塊鏈就像是一個分布式數據庫,這個數據庫維護了一個不斷增長的記錄鏈表。如果熟悉關系型數據庫,你應該知道一張表裏有很多行的數據。現在,對數據進行批(batch)量處理(比如每批 100 行),並將每個處理的批次相連。就可以形成一個區塊鏈了!在區塊鏈裏,每個批次的數據就叫一個塊(block),塊裏的每一行就叫一筆交易(transaction)。

現在,你對以太坊已經有了基本了解,我們可以開始構建投票的 dapp 了。這將會加強你對以太坊的認識,並且初略了解以太坊的功能。

以太坊開發環境搭建

Linux

示例是 Ubuntu 16.04 下的學習環境搭建,你只需要成功安裝了 nodejs 和 npm,就可以繼續項目的下一步了。

我們通過 npm 安裝 ganache 和 web3 包來為以太坊教程提供支撐。我們也需要安裝 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 --version
v7.4.0 $ npm --version 4.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) 0x208e02303fe29be3698732e92ca32b88d80a2d36 Private Keys ================== (0) a6de9563d3db157ed9926a993559dc177be74a23fd88ff5776ff0505d21fed2b (1) 17f71d31360fbafbc90cad906723430e9694daed3c24e1e9e186b4e3ccf4d603 (2) ad2b90ce116945c11eaf081f60976d5d1d52f721e659887fcebce5c81ee6ce99 (3) 68e2288df55cbc3a13a2953508c8e0457e1e71cd8ae62f0c78c3a5c929f35430 (4) 9753b05bd606e2ffc65a190420524f2efc8b16edb8489e734a607f589f0b67a8 (5) 6e8e8c468cf75fd4de0406a1a32819036b9fa64163e8be5bb6f7914ac71251cc (6) c287c82e2040d271b9a4e071190715d40c0b861eb248d5a671874f3ca6d978a9 (7) cec41ef9ccf6cb3007c759bf3fce8ca485239af1092065aa52b703fd04803c9d (8) c890580206f0bbea67542246d09ab4bef7eeaa22c3448dcb7253ac2414a5362a (9) eb8841a5ae34ff3f4248586e73fcb274a7f5dd2dc07b352d2c4b71132b3c73f0

HD Wallet ================== Mnemonic: cancel better shock lady capable main crunch alcohol derive alarm duck umbrella Base 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 --version
v7.10.0 $ npm --version 4.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) 0x208e02303fe29be3698732e92ca32b88d80a2d36 Private Keys ================== (0) a6de9563d3db157ed9926a993559dc177be74a23fd88ff5776ff0505d21fed2b (1) 17f71d31360fbafbc90cad906723430e9694daed3c24e1e9e186b4e3ccf4d603 (2) ad2b90ce116945c11eaf081f60976d5d1d52f721e659887fcebce5c81ee6ce99 (3) 68e2288df55cbc3a13a2953508c8e0457e1e71cd8ae62f0c78c3a5c929f35430 (4) 9753b05bd606e2ffc65a190420524f2efc8b16edb8489e734a607f589f0b67a8 (5) 6e8e8c468cf75fd4de0406a1a32819036b9fa64163e8be5bb6f7914ac71251cc (6) c287c82e2040d271b9a4e071190715d40c0b861eb248d5a671874f3ca6d978a9 (7) cec41ef9ccf6cb3007c759bf3fce8ca485239af1092065aa52b703fd04803c9d (8) c890580206f0bbea67542246d09ab4bef7eeaa22c3448dcb7253ac2414a5362a (9) eb8841a5ae34ff3f4248586e73fcb274a7f5dd2dc07b352d2c4b71132b3c73f0

HD Wallet ================== Mnemonic: cancel better shock lady capable main crunch alcohol derive alarm duck umbrella Base 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 [email protected] 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 編譯器進行了一些改進,如果用戶忘記了對私有函數進行標記導致了外部可以調用私有函數,編譯器會捕獲這個問題。 這裏 可以看到所有的可見性說明符。

你也會在一些函數上看到一個修飾符 view。它通常用來告訴編譯器函數是只讀的(也就是說,調用該函數,區塊鏈狀態並不會更新)。所有的修飾符都可以在 這裏 看到。

編譯智能合約

我們將會使用上一節安裝的 solc 庫來編譯代碼。如果你還記得的話,之前我們提到過 web3js 是一個庫,它能夠讓你通過 RPC 與區塊鏈進行交互。我們將會在 node 控制臺裏用這個庫部署合約,並與區塊鏈進行交互。

首先,在終端中運行 node 進入 node 控制臺,初始化 web3 對象,並向區塊鏈查詢獲取所有的賬戶。

確保與此同時 ganache 已經在另一個窗口中運行

為了編譯合約,先從 Voting.sol 中加載代碼並綁定到一個 string 類型的變量,然後像下邊這樣對合約進行編譯。

$ node In 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 的更多內容。

教程參考匯智網的DAPP開發入門教程,如果大家等不及博客更新,也可以直接訪問這個以太坊教程。

以太坊教程:搭建環境、編寫編譯一個智能合約