web3.0時代正悄悄來臨。如果你想開發一個web3項目,或者想要未來從事web3工作,充實自己的web3履歷,本文就是一篇很好的DApp開發技術入門教程。
這篇文章的主要內容包括:
智能合約創建和部署
Solidity語言入門
hardhat框架使用及本地環境搭建
本文較長,包括 20 余張圖片、1 個 Hello-World 版本的 web3項目示例,以及完整的項目程式碼及註釋。如果現在你正在使用手機閱讀,建議先收藏本文;之後打開電腦,沿著本文的思路,仔細閱讀。
一、Hardhat 是什麼?
Hardhat框架,是一個以太坊DApp開發的本地整合開發套件。經常與之對比的是 Hardhat vs Truffle。相比其它作為web3基礎設施的開發工具,Hardhat 更加輕量,採用外掛化的思想,非常適合作為新手dapp開發入門的工具。
Hardhat框架,一個輕量級DApp開發套件
二、環境準備 —— 安裝 Node.js
在使用 Hardhat 進行開發以前,首先需要在本地安裝 Node 環境。
nodejs下載
這裡是nodejs官網的下載地址,根據自己操作系統的配置,選擇合適的版本下載。
這裡要注意,如果電腦上已經安裝過,記得升級到 node v14 及以上的版本,更早的版本不支持 Hardhat。
看一下是否安裝成功,分別輸入:
nodejs安裝是否成功
我這裡是 Windows 系統,用 PowerShell 執行一下上面幾條命令,可以看到已經安裝成功了。
三、開始第一個web3項目
1. 初始化
首先創建一個目錄 hardhat-demo,進到這個目錄里,執行 npx hardhat init 命令:
這時會問你幾個問題,一路回車即可。
使用Hardhat初始化web3項目
npx hardhat init 的作用是:按照模板創建了一個示例項目。當出現 「Project created」 字樣時,代表項目創建成功。
可以看到,在上面的 截圖里,提示了我們要安裝依賴。為了能讓這個示例項目跑起來,還需要安裝幾個依賴模塊:
安裝完以後,這個目錄下的文件應該有這些:
Hardhat初始化DApp項目的目錄結構
這樣,你就成功完成了第一個步驟。
2. 項目中的文件作用
創建好這個示例項目以後,這裡來分析一下這些文件的作用。這一部分略微有一些枯燥,你也可以先閱讀「3. 智能合約的編譯、部署和測試」這一部分,之後再來看這些文件的作用。
① node_modules/、package-lock.json 和 package.json
這些是 node 項目的必須組成部分,包括了項目的配置資訊、安裝的依賴模塊等,這裡可以先無視。
② contracts/Greeter.sol
這個文件是項目中的重點,叫智能合約文件。什麼是智能合約呢?你可以把智能合約,同樣理解為一種可以運行的 程式。只不過這個 程式比較特殊,它是運行在以太坊的 EVM 虛擬機 環境上。並且, 程式本身、 程式的輸入輸出、運行結果等,對所有人可見。
Solidity語言,是智能合約開發的主流語言之一。Solidity語言的入門教程,不是本文涉及的重點,這裡只是簡單提一下。
簡單用 Java 類比一下:
原來你寫了一段 Java 程式碼,放進一個源文件叫作 HelloWorld.java,用 javac 執行編譯,最終在自己的電腦或者 伺服器上,被 JVM 虛擬機執行;現在寫了一段 Greeter.sol 程式碼,它也可以被編譯,被執行,只不過運行環境變成了以太坊的 EVM
初始化項目以後,自動生成的程式碼是這樣的:
第 1 行 pragma solidity ^0.8.0;,聲明了 License,比如 GPL-3.0;
第 2 行 pragma solidity ^0.8.0;,聲明了編譯器版本,這裡面強制指定了版本不得低於 0.8.0,也不能高於 0.9.0;
第 4 行 import"hardhat/console.sol"; 導入了其它合約文件,這裡面的 hardhat/console.sol 文件,是 Hardhat 框架自帶的,是一個用於方便調試的合約文件,源碼在這裡;
第 6 行 contract Greeter 開始,就是合約的主體部分。從結構上看,它很像是在 C++ 或者 Java 中定義一個類,也包括了欄位變數、構造方法、讀方法、寫方法等。這裡面出現了幾個特殊的關鍵字:
contract :聲明一個合約;
memory:和 storage 關鍵字相反,代表了變數只會臨時放在記憶體中,不會存儲在合約的狀態中;
view:聲明該方法為只讀方法,不會改變合約本身的狀態。
③ scripts/sample_scripts.js
這個 JavaScript 文件的作用,是將剛才的 Greeter.sol 智能合約編譯並部署到鏈上。
在註釋中寫上了各行程式碼的作用。這裡要注意幾點:
合約的部署需要一定的時間,因為使用 await greeter.deployed() 非同步方法,等待合約部署完成。
用 Java 程式碼類比一下:Greeter 這個合約像是一個類,而每次部署得到的 greeter 像是 new 了一個類的對象。因此每次部署,都會生成出不同的對象,得到的合約地址也就不同。
④ test/sample_test.js
單元測試對於 web3開發來說同樣重要。sample_test.js 這個文件就是一個單元測試的文件,使用了 chai 這個測試框架:
⑤ hardhat.config.js
接下來,我們會啟動 HardHat,進行區塊鏈本地環境的搭建部署。在正式啟動之前,需要進行一些配置。hardhat.config.js 這個文件,就是在 Hardhat 啟動時,默認要讀取的配置文件。
這裡可以看到,文件的內容可以分為 3 個部分:
聲明依賴的模塊。
聲明啟動時執行的任務:在官方文檔裡面有更加詳細的說明,這裡的示例 task 的作用是:啟動 Hardhat 時, 列印出本地這條鏈的默認帳戶。
聲明配置項:更詳細的說明可以參考官方文檔,這裡說明一下常見配置的含義:
在「1. 初始化」中,執行了 npx hardhat init 以後,會生成出一個默認的配置文件。一般來說,使用這個默認配置即可,不需要更改。
這裡面有一個問題,上面的配置中,同時出現了 localhost 和 hardhat 兩種網路。它們有什麼不同呢?這裡暫時先不提,在 「3. 智能合約的編譯、部署和測試」這一部分中,你就會找到答案。
這樣,項目中各個文件的作用就介紹完畢。可能略微有點枯燥,馬上就可以進入實戰環節了。
3. 智能合約的編譯、部署和測試
① MetaMask錢包下載、安裝及帳戶新建
MetaMask 是什麼呢?它是一個以太坊生態下的錢包,可以管理你的帳戶,支持多種網路。
MetaMask錢包本質上是一個瀏覽器外掛,這裡有它的下載地址(可能需要科學上網),然後像正常添加其它瀏覽器外掛一樣,添加上去就好。
MetaMask外掛
接下來可以通過助記詞的方式,生成一個新帳戶;也可以通過粘貼私鑰的方式,導入你原有的帳戶。
MetaMask錢包導入帳戶
這樣,我們的 MetaMask 錢包就準備好了。
② 在本地網路上部署合約
接下來我們要啟動一個本地區塊鏈網路節點。
首先打開一個 Terminal/Powershell 窗口,執行 npx hardhat node 命令:
Hardhat啟動本地區塊鏈網路節點
這個命令的作用是:按照 hardhat.config.js 中聲明的配置,啟動一個本地區塊鏈網路的節點。在每次啟動時,默認會提供 20 個錢包帳戶和私鑰,每個錢包提供 10000 個 ETH 做測試。
可以看到,Hardhat 啟動時,把這 20 個帳戶的資訊 列印了出來。為什麼會 列印帳戶資訊呢?因為在 hardhat.config.js 中定義了這個執行任務;如果你忘記了,可以回過頭看一下。
啟動成功了,還可以用 MetaMask 這個錢包再驗證一下。
新增一個 localhost 網路,注意鏈 ID 要和 hardhat.config.js 中的 chainId 相同,默認是 31337.
MetaMask Localhost本地網路配置
導入一個帳戶,這裡我選擇了那 20 個自動帳戶中的第 1 個,把私鑰粘貼進去。
這裡注意一下,這些帳戶僅僅是為了本地測試使用,千萬不要在以太坊主網使用這些帳戶地址!切記!
現在,本地網路環境已經就緒,我們把 contracts/Greeter.sol 部署到本地網路上。
打開另一個 Terminal/PowerShell,執行 npx hardhat run .\scripts\sample-script.js --network localhost:
於是會執行 scripts/sample_scripts.js 中的 main 方法,並且 列印出了 Greeter 這個合約的部署地址。
使用Hardhat部署智能合約到本地區塊鏈網路上
同樣地,在啟動本地網路的窗口中,也可以看到剛才這個合約的部署情況:
Hardhat部署智能合約成功
在部署合約時,會執行 constructor 構造函數,所以 console.log(“Deploying a Greeter with greeting:”, _greeting); 這句被執行並 列印出來。
部署合約需要消耗 gas,所以可以看到第一個帳戶中的餘額不再是 10000 個 ETH 了(默認使用第一個帳戶來操作):
MetaMask查看帳戶
再執行一次 npx hardhat run .\scripts\sample-script.js --network localhost,會發現雖然是同一份合約程式碼,但是合約地址發生了變化:
Hardhat部署同一份智能合約程式碼
正如在 「③ scripts/sample_scripts.js」 中所說,用 Java 程式碼類比一下:Greeter 這個合約像是一個類,而每次部署得到的 greeter 像是一個類的對象,因此每次部署,生成出了不同的對象,得到的合約地址也就不同。
我們把 scripts/sample_scripts.js 稍作修改,就可以得到web3版本的 Hello World 了:
到這步為止,我們的 Greeter 合約就成功在本地網路上部署好了,也成功使用 MetaMask 錢包,進行了本地網路連接、測試帳戶導入。
③ Hardhat 其它常見的命令
剛才我們學習了 Hardhat框架的 2 個命令:
npx hardhat node 命令,啟動區塊鏈網路一個本地節點
npx hardhat run .\scripts\sample-script.js --network localhost 命令,把合約部署到了本地網路上。
這一部分,會說明一下其它 Hardhat 的實用命令。
npx hardhat test
這個命令用於執行單元測試,在示例中,也就是運行了 test/sample_test.js 這個文件:
使用Hardhat進行Web3技術開發:單元測試
這代表測試成功。我們稍微修改一下 sample_test.js 文件:
再次執行命令,就會發現測試失敗了:
使用Hardhat進行Web3項目開發:單元測試失敗情況
你可能會問一個問題:在 sample_test.js 的程式碼中,同樣出現了合約的部署語句,那麼這個合約是被部署到了哪裡呢?再次被部署到了 localhost 這個本地網路上嗎?
答案是否定的。
還記得在 「⑤ hardhat.config.js」 一節中提過,有兩個很相似的網路配置: localhost 和 hardhat。當執行 npx hardhat test 命令時,會內置創建 hardhat 網路,並在 hardhat 網路上完成合約部署、方法調用等,不會部署在 localhost 網路上。這一點一定要注意。
npx hardhat console
這個命令的作用是啟動一個控制台 程式,方便互動式輸入輸出。例如輸入 config 查看配置情況:
使用Hardhat進行web3開發:啟動控制台console
在 sample_scripts.js 中的程式碼語句,可以換成在 console 中執行:
使用Hardhat進行web3開發:啟動控制台console
npx hardhat compile
在執行 npx hardhat run .\scripts\sample-script.js --network localhost 部署合約的時候,其實 hardhat 偷偷幫你做了一件事情:編譯。
我們把 artifacts 和 cache 目錄刪掉,現在的目錄結構應該是這樣:
Dapp開發:項目目錄結構
現在我們執行 npx hardhat compile 命令,執行成功后,會發現剛才刪掉的 artifacts 和 cache 目錄,又重新生成出來了。
使用Hardhat進行智能合約的編譯
所以,這個命令的作用就是編譯。cache 是編譯出來的緩存資料夾。artifacts 目錄下的文件很重要,看一下 artifacts/contracts/Greeter.sol/Greeter.json 這個文件:
這個文件和原始文件 contracts/Greeter.sol 有點兒像,又有點兒不像。它就是源文件編譯出來的樣子。這個文件很重要,我們之後還會用到它。
npx hardhat clean
這個命令和 npx hardhat compile 的作用恰好相反,是把編譯出來的文件清理一下。
最後,還有一個重要的命令,叫作 npx hardhat help,這條命令會展示 npx hardhat 系列命令的用法:當你忘記的時候,就可以用這條命令查詢一下。
使用Hardhat進行區塊鏈項目開發:查看幫助help
四、結語
這就到了結語部分?
是的。跟隨本文,你已經掌握了 Hardhat 開發框架的基本用法;創建了一個web3項目;編寫修改了智能合約;執行了單元測試;啟動運行了本地區塊鏈節點;將合約文件成功進行編譯和部署;還安裝了 MetaMask 錢包,並連接了本地網路和測試帳戶進行測試。
但是,現在這個項目,和我們編寫的第一個 C++ Hello-World 控制台 程式一樣,還缺乏一個對用戶友好的前端頁面。如何快速編寫一個前端頁面?如何連接用戶錢包?如果調用智能合約的方法?這些會放在下一篇文章中進行講解。