智能合約的優點
與傳統合同相比,智能合約有一些顯著優點:

- 不需要中間人
- 費用低
- 代碼就是規則
- 區塊鏈網絡中有多個備份,不用擔心丟失
- 避免人工錯誤
- 無需信任,就可履行協議
- 匿名履行協議
以太坊(Ethereum) – 智能合約開發概述
支持智能合約的區塊鏈
雖然以太坊(Ethereum)是最流行支持智能合約的區塊鏈平台,但它並不是唯一支持智能合約的平台。
超級賬本(Hyperledger) 是Linux基金會於2015年發起的推進區塊鏈數字技術和交易驗證的開源項目。通過創建分布式賬本的公開標准,實現虛擬和數字形式的價值交換,例如資產合約、能源交易、結婚證書、能夠安全和高效低成本的進行追蹤和交易。
另外,還有其他很多區塊鏈平台支持智能合約,可以參考相關資料。
以太坊(Ethereum)智能合約開發工具
通常,開發智能合約需要用到工具:
- Mist – 以太坊節點/錢包。
- Truffle 框架 – 流行的以太坊開發框架,內置了智能合約編譯、鏈接、部署等功能。
- Metamask – Chrome插件方式的以太坊節點/錢包。
- Remix – Remix是一個基於web瀏覽器的智能合約開發環境(IDE)。
以太坊(Ethereum)智能合約開發語言
目前主要的智能合約開發語言是 Solidity語言,是一種開發以太坊智能合約的靜態高級語言,語法類似於JavaScript。
還有另外一些智能合約開發語言:
等等。
以太坊(Ethereum) – 智能合約開發環境搭建
為了構建開發智能合約或者dApp,我們需要安裝以下模塊:
- Node 與 NPM
- Truffle 框架
- Ganache
- Metamask
- VScode 與 Solidity插件
Node 與 NPM
Truffle 框架依賴Node,需要使用npm安裝。
首先需要安裝node,npm會同時安裝,下載node,按提示安裝。
安裝完后,可以驗證一下node版本:
$ node -v
Truffle 框架
Truffle框架是流行的以太坊開發框架,內置了智能合約編譯、鏈接、部署等功能。
使用npm安裝Truffle框架:
$ npm install -g truffle
驗證truffle安裝:
$ truffle --version Truffle v5.0.35 - a development framework for Ethereum ...
Ganache
在實際的以太坊網絡上測試、部署Dapp或智能合約,需要消耗Gas。Ganache可以在本地創建區塊鏈網絡來測試我們的程序。
可以從Truffle Framework網站下載Ganache來安裝。它將創建一個本地區塊鏈網絡,給我們分配10個外部賬號,每個帳戶都有100個假的以太幣。
Metamask
Metamask是一個Chrome插件形式的以太坊節點/錢包。
我們可以使用Metamask連接到本地區塊鏈網絡或實際的以太坊網絡,並與我們的智能合約交互。
要安裝Metamask,請在谷歌Chrome web store中搜索Metamask Chrome插件並安裝。一旦安裝,請確保打開啟用按鈕。安裝后,你會在Chrome瀏覽器的右上角看到狐狸圖標。
VS code 與 Solidity插件
推薦使用vs code編輯器編寫solidity代碼,vs code可以安裝一下Solidity插件,以便支持語法高亮功能。
以太坊(Ethereum) – Ganache本地區塊鏈
我們安裝了Ganache。現在啟動Ganache,創建本地的以太坊區塊鏈網絡。
主界面
本地區塊鏈可以模擬公共區塊鏈,開發人員可以在本地區塊鏈上測試智能合約。打開Ganache,界面如下圖所示:

本地區塊鏈缺省有10個外部賬號,每個賬號都有100個假的以太幣,這些可以通過設置改變。
Ganache界面中有下面幾個主要頁面:
- ACCOUNTS – 賬號頁面,這顯示了自動生成的所有帳戶及其余額。
- BLOCKS – 區塊頁面,顯示了在本地區塊鏈網絡上挖掘的每個區塊,及其Gas成本和包含的交易。
- TRANSACTIONS – 交易頁面,列出了在本地區塊鏈上發生的所有交易。
- CONTRACS – 合約頁面
- EVENTS – 事件頁面
- LOGS – 日志頁面
搜索區塊或交易
界面頂部的搜索欄,可以讓你搜索本地區塊鏈網絡上的區塊或交易。
設置
可以通過設置來定制Ganache的一些功能,單擊主界面右上角的圖標進入設置頁面。

以下是一些主要設置:
- SERVER – 服務器設置頁面,管理關於網絡連接的詳細信息,比如網絡id、端口、主機名和自動挖掘狀態。
- ACCOUNTS & KEYS – 帳戶和密鑰頁,設置自動生成的帳戶數量及其余額,缺省10個賬號,每個賬號余額是100 ether。
- CHAIN – 鏈頁,讓你為網絡設置Gas限制和Gas價格。
- 高級設置 – 日志選項設置,比如保存日志文件和配置詳細輸出的能力。
請注意,在更改了新的設置之后,必須Restart(設置頁面右上角)才能生效。
以太坊(Ethereum) – 開發智能合約
我們將使用truffle創建一個智能合約項目,該智能合約的功能是可以獲取值和設置值。
1. 初始化項目
首先創建項目目錄:
$ mkdir mydapp
$ cd mydapp
然后使用truffle init初始化項目,將生成項目模板文件:
$ truffle init
我們可以查看一下生成的項目目錄:
G:\qikegu\ethereum\mydapp>tree /f 卷 數據 的文件夾 PATH 列表 卷序列號為 0C52-9CF4 G:. │ truffle-config.js │ ├─contracts │ Migrations.sol │ ├─migrations │ 1_initial_migration.js │ └─test
- contracts 目錄 智能合約源文件目錄,現在已經有了一個
Migrations.sol源文件,功能是遷移/部署/升級智能合約。 - migrations 目錄 遷移文件目錄,遷移文件都是javascript腳本,幫助我們把智能合約部署到以太坊。
- test 目錄 測試代碼目錄。
- truffle-config.js 文件 Truffle項目配置文件,例如可以在里面配置網絡。
添加package.json文件
package.json是npm用來管理包的配置文件,在項目根目錄下創建此文件,內容如下:
{ "name": "ethereum-demo", "version": "1.0.0", "description": "以太坊demo", "main": "truffle-config.js", "directories": { "test": "test" }, "scripts": { "dev": "lite-server", "test": "echo \"Error: no test specified\" && sexit 1" }, "author": "kevinhwu@qikegu.com", "license": "ISC", "devDependencies": { "@truffle/contract": "^4.0.33", "dotenv": "^8.1.0", "lite-server": "^2.5.4", "truffle-hdwallet-provider": "^1.0.17" } }
關於依賴的包,可以在后面章節中,用到時逐個安裝。
2. 添加智能合約源文件
在contracts 目錄中創建一個新文件MyContract.sol,內容如下所示:
// 聲明solidity版本 pragma solidity ^0.5.0; // 聲明智能合約MyContract,合約的所有代碼都包含在花括號中。 contract MyContract { // 聲明一個名為value的狀態變量 string value; // 合約構造函數,每當將合約部署到網絡時都會調用它。 // 此函數具有public函數修飾符,以確保它對公共接口可用。 // 在這個函數中,我們將公共變量value的值設置為“myValue”。 constructor() public { value = "myValue"; } // 本函數讀取值狀態變量的值。可見性設置為public,以便外部帳戶可以訪問它。 // 它還包含view修飾符並指定一個字符串返回值。 function get() public view returns(string memory ) { return value; } // 本函數設置值狀態變量的值。可見性設置為public,以便外部帳戶可以訪問它。 function set(string memory _value) public { value = _value; } }
這個智能合約的功能是可以獲取值和設置值。
3. 編譯項目
現在讓我們編譯項目:
項目目錄下執行命令:
$ truffle compile
等編譯完成,可以看到多了一個build目錄,該目錄下生成了新文件:./build/contract/MyContract.json
這個文件是智能合約ABI文件,代表“抽象二進制接口”。這個文件有很多作用,其中2個重要作用:
- 作為可在Ethereum虛擬機(EVM)上運行的可執行文件
- 包含智能合約函數的JSON表示,以便外部客戶端可以調用這些函數
以太坊(Ethereum) – 部署智能合約到Ganache
接下來,我們將編譯好的智能合約部署到本地的Ganache區塊鏈網絡。步驟如下:
- 更新項目的配置文件,修改網絡配置連接到本地區塊鏈網絡(Ganache)。
- 創建遷移腳本,告訴Truffle如何部署智能合約。
- 運行新創建的遷移腳本,部署智能合約。
1. 更新配置文件
更新項目的配置文件,修改網絡配置連接到本地區塊鏈網絡(Ganache)。
打開位於項目根目錄下的truffle-config.js文件,修改內容如下:
module.exports = { networks: { development: { host: "127.0.0.1", port: 7545, network_id: "*" // Match any network id } }, solc: { optimizer: { enabled: true, runs: 200 } } }
這些網絡配置,包括ip地址、端口等,應該與Ganache的網絡配置匹配:

2. 創建遷移腳本
接下來,我們將在migrations目錄中創建遷移腳本,告訴Truffle如何部署智能合約,在該目錄中創建文件2_deploy_contracts.js。
注意,在migrations目錄中所有文件都有編號,作用是讓Truffle知道執行它們的順序。
2_deploy_contracts.js文件內容如下:
var MyContract = artifacts.require("./MyContract.sol"); module.exports = function(deployer) { deployer.deploy(MyContract); };
上面的代碼中:
- 首先,
require了創建的合約,並將其分配給一個名為“MyContract”的變量。 - 接着,將合約加入部署清單,運行遷移命令時合約將被部署。
3. 執行遷移命令
現在讓我們從命令行執行遷移命令, 部署智能合約。
$ truffle migrate
執行詳情如下:
G:\qikegu\ethereum\mydapp>truffle migrate Compiling your contracts... =========================== > Everything is up to date, there is nothing to compile. Starting migrations... ====================== > Network name: 'development' > Network id: 5777 > Block gas limit: 0x6691b7 1_initial_migration.js ====================== Deploying 'Migrations' ---------------------- > transaction hash: 0xe62fb8a27c9ccc894562fbd7a7797526ad9323ab67a44516ae342642bf4ffcc6 > Blocks: 0 Seconds: 0 > contract address: 0x168A7247B58786edd259502948f5Bf9449C863AD > block number: 1 > block timestamp: 1568189958 > account: 0x29920e756f41F8e691aE0b12D417C19204371E91 > balance: 99.99477214 > gas used: 261393 > gas price: 20 gwei > value sent: 0 ETH > total cost: 0.00522786 ETH > Saving migration to chain. > Saving artifacts ------------------------------------- > Total cost: 0.00522786 ETH 2_deploy_contracts.js ===================== Deploying 'MyContract' ---------------------- > transaction hash: 0xe9dcef6f70332e476684e8f93ab96969af53920555161054f1f4bcc6277116fb > Blocks: 0 Seconds: 0 > contract address: 0x4D3CFaF8457CEA76c0409f989f9870115B4d2d82 > block number: 3 > block timestamp: 1568189959 > account: 0x29920e756f41F8e691aE0b12D417C19204371E91 > balance: 99.98804272 > gas used: 294448 > gas price: 20 gwei > value sent: 0 ETH > total cost: 0.00588896 ETH > Saving migration to chain. > Saving artifacts ------------------------------------- > Total cost: 0.00588896 ETH Summary ======= > Total deployments: 2 > Final cost: 0.01111682 ETH receipt: { transactionHash: '0x83be6ef86fe542b3c94ae1dd5f2e04570c199d6b2e7997af60f3d91cda9259ec', transactionIndex: 0, blockHash: '0x6e58c2c77b5998004b8a8c66760ca923814865307c69f1c779673cc2cbca06bc', blockNumber: 5, from: '0x29920e756f41f8e691ae0b12d417c19204371e91', to: '0x4d3cfaf8457cea76c0409f989f9870115b4d2d82', gasUsed: 33501, cumulativeGasUsed: 33501, contractAddress: null, logs: [], status: true, logsBloom: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', v: '0x1c', r: '0xdaf1578a7987ec5d4e7d25c4b66f570d97f880b783d3403b54fa7eb30b1ab836', s: '0x4024f2b26bab6277cc86da9727a9bccc1ba7832773b9c2781b265f8dd87df46f', rawLogs: [] }, logs: [] }
可以看到,我們已經將智能合約成功部署到本地的Ganache區塊鏈網絡。
以太坊(Ethereum) – 使用 truffle console 訪問智能合約
truffle console 是區塊鏈開發人員的強大工具,這是一個命令行工具,可以在命令行中執行javascript代碼,與智能合約進行交互。這對於開發智能合約非常有用。
我們已經成功地將智能合約部署到本地區塊鏈網絡,接下來我們將使用 truffle console 與智能合約進行交互。
啟動 truffle console:
$ truffle console
進入控制台后,讓我們獲取已部署智能合約的一個實例,看看能否從該合約中讀取value值。從控制台運行以下代碼:
MyContract.deployed().then((instance) => { app = instance } )
這里MyContract是之前在遷移文件中創建的變量名稱,使用deployed()函數獲取一個已部署合約的實例,並將其分配給promise回調函數中的一個app變量。
現在可以獲取智能合約中的value值:
app.get() // => 'myValue'
給value設置一個新值:
app.set('New Value')
重新獲取智能合約中的value值:
app.get() // => 'New Value'
可以通過以下命令退出truffle console:
.exit
以太坊(Ethereum) – 智能合約測試(truffle test)
類似Java中JUnit單元測試工具,Trfuffle test可以幫助我們對智能合約項目進行白盒測試。
對於區塊鏈項目,測試顯得尤其重要,因為部署合約、遷移合約的成本都是相當高的,都要消耗Gas。
編寫測試代碼
現在讓我們對前面章節中創建的智能合約,編寫一些測試代碼。整個測試過程模擬對智能合約MyContract獲取value值、設置value值的過程。
先確保MyContract已經正確部署到Ganache本地區塊鏈網絡中。測試中將會用到Mocha測試框架,與Chai斷言庫,但Truffle已經集成了這些庫。
測試代碼用JavaScript編寫,模擬與智能合約的交互,就像使用truffle console所做的那樣。
在項目根目錄下的test目錄中,添加測試腳本文件: MyContract.js
MyContract.js中的測試代碼:
// 首先,`require`合約並將其分配給一個變量`MyContract` const MyContract = artifacts.require('./MyContract.sol'); // 調用“contract”函數,並在回調函數中編寫所有測試 // 回調函數提供一個“accounts”變量,表示本地區塊鏈上的所有帳戶。 contract('MyContract', (accounts) => { // 第1個測試:調用get()函數,檢查返回值,測試合約中value初始值是否是: 'myValue' it('initializes with the correct value', async () => { // 獲取合約實例 const myContract = await MyContract.deployed() const value = await myContract.get() // 使用斷言測試value的值 assert.equal(value, 'myValue') }) // 第2個測試: 調用set()函數來設置value值,然后調用get()函數來確保更新了值 it('can update the value', async () => { const myContract = await MyContract.deployed() myContract.set('New Value'); const value = await myContract.get() assert.equal(value, 'New Value') }) })
代碼說明,請見注釋。
運行測試腳本
執行命令行運行測試:
$ truffle test
測試詳情:
G:\qikegu\ethereum\mydapp>truffle test Using network 'development'. Compiling your contracts... =========================== > Everything is up to date, there is nothing to compile. Contract: MyContract √ initializes with the correct value (76ms) √ can update the value (78ms) 2 passing (188ms)
以太坊(Ethereum) – 連接公鏈
本篇介紹如何將Truffle項目連接到公共區塊鏈網絡。
到目前為止,我們連接的都是在本地區塊鏈(Ganache),接下來將連接以太坊公鏈。
以太坊公鏈除了主網,還有多個測試網絡。主網(Mainnet)是正式的以太坊網絡,里面的以太幣是真正有價值的,測試網絡中的以太幣沒有價值,只用於測試。
我們最終目標是連接到主網,但先連接到測試網絡Kovan,雖然本地區塊鏈網絡(Ganache)也能測試,但與公鏈還是有區別的。
連接到公鏈的步驟如下:
- 設置錢包來管理公鏈帳戶
- 連接到以太坊節點
- 更新項目設置
- 訪問以太坊節點
設置錢包
首先需要設置一個錢包,來管理我們的公鏈帳戶。
簡單起見,可以借用Ganache本地區塊鏈錢包,由於區塊鏈的工作原理,這個錢包在公共區塊鏈和本地區塊鏈上都是有效的。
打開Ganache,主界面上可以看到一個名為“MNEMONIC”的部分:

這是一個種子短語,用於構建由Ganache管理的錢包。我們可以使用這個種子短語加密重建錢包,來連接到公鏈。
復制這個值,保存到一個秘密文件,MNEMONIC是一個秘密值,需要保密。在項目根目錄中創建一個.env文件,保存MNEMONIC值,如下所示:
MNEMONIC="你的mnemonic"
連接以太坊節點
現在已經創建了錢包,下一步需要訪問Ethereum節點,以便連接到公共區塊鏈網絡。
有幾種方法可以做到這一點,可以使用Geth或Parity運行自己的Ethereum節點。但這需要從區塊鏈下載大量數據並保持同步,很麻煩。
比較方便的方法是,使用Infura訪問Ethereum節點。Infura是一個免費提供Ethereum節點的服務。
在Infura上注冊賬號,創建項目,在項目詳情頁上可以查看API KEY:

使用API KEY,就可以訪問以太坊網絡節點。
在.env文件中添加Infura api key的配置:
INFURA_API_KEY="https://kovan.infura.io/v3/543526cd4d3846acbc3826484e934564" MNEMONIC="你的mnemonic"
更新項目設置
接下來使用MNEMONIC與INFURA_API_KEY,更新項目的網絡配置,以便連接到公共區塊鏈網絡。
修改truffle-config.js文件:
// 導入dotenv庫創用於讀取`.env`文件中的設置 require('dotenv').config(); // 導入truffle-hdwallet-provider庫重建錢包 const HDWalletProvider = require('truffle-hdwallet-provider'); module.exports = { networks: { development: { host: "127.0.0.1", // Localhost (default: none) port: 7545, // Standard Ethereum port (default: none) network_id: "*", // Any network (default: none) }, // Useful for deploying to a public network. // NB: It's important to wrap the provider as a function. kovan: { provider: () => new HDWalletProvider( process.env.MNEMONIC, process.env.INFURA_API_KEY ), gas: 5000000, gasPrice: 25000000000, network_id: 42 }, }, solc: { optimizer: { enabled: true, runs: 200 } } }
可以看到,我們使用了.env配置文件中的MNEMONIC與INFURA_API_KEY配置了kovan網絡。
由於用到了dotenv與truffle-hdwallet-provider這2個庫,我們需要先安裝:
切換到項目目錄,執行以下命令
npm install dotenv --save-dev
npm install truffle-hdwallet-provider --save-dev
注意 安裝truffle-hdwallet-provider時,如果出現node-gyp相關的錯誤,可參考這里解決。
訪問以太坊節點
使用truffle console連接到公共區塊鏈網絡:
$ truffle console --network kovan
要驗證連接,可以從區塊鏈中讀取一些數據,獲取一些關於最新區塊的信息,在控制台上執行:
web3.eth.getBlock('latest').then(console.log)
輸出
{ author: '0x03801efb0efe2a25ede5dd3a003ae880c0292e4d',
difficulty: '340282366920938463463374607431768211454',
extraData:
'0xde830206028f5061726974792d457468657265756d86312e33362e30826c69',
gasLimit: '0x7a1200',
gasUsed: '0x17d23',
hash:
'0xc7390c4f492c8c1da60608135fc9e05930123b645b39f221cba33d8b3c577b2a',
logsBloom:
'0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000080000000000000000000100000008000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400800000000000010000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009000000008000000',
receiptsRoot:
'0x3d05bb2ed4fcc90234eea6d840e7d0e3ce7f598a15e5314536b17bcd11c78b5b',
sealFields:
[ '0x84175e8801',
'0xb84155a8cdb108dccec1d314124058fa6f22e7400ee200db0a94b7b165e4c3454c1818cc05f815cb7ce48f7a88b8401515740311a3566d9cf079428d506a6daca50101' ],
sha3Uncles:
'0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347',
signature:
'55a8cdb108dccec1d314124058fa6f22e7400ee200db0a94b7b165e4c3454c1818cc05f815cb7ce48f7a88b8401515740311a3566d9cf079428d506a6daca50101',
size: 877,
stateRoot:
'0x03af5adce52a81ce5d332cddb9955e344214bff00859b78868116e1e839efdf7',
step: '392071169',
timestamp: 1568284676,
totalDifficulty: '4524524338444961608702071789512829094373049115',
transactions:
[ '0xded7fed0842fd65ec808bc3652ec4175bc190acc11345c49c44b1fb5d954610f',
'0x7e9112a46fa3c07aad813ea86355b15eebb44023c040d198ee7d15d379bbc2be' ],
transactionsRoot:
'0x0dd10d90686dda2684bd0ba70d1c9e1d9a5302c30ca75eb2c5b07a7b6e4498b9',
uncles: [] }
可以看到,已經成功連接到了公鏈。
以太坊(Ethereum) – 部署智能合約到公鏈
現在,我們將智能合約部署到公鏈。步驟如下:
- 部署需要消耗Gas,獲取測試以太幣用於部署
- 部署智能合約
- 驗證部署
獲取測試以太幣
部署需要消耗Gas,Gas需要支付以太幣,我們部署到的是公鏈測試網Kovan,網絡中的以太幣沒有市場價值。
可以從Kovan faucet Gitter聊天室獲取測試用的偽以太幣。只需把錢包地址發送出去,約5分鍾內,有人會給你發測試用的偽以太幣。
打開Ganache並復制列表中第一個帳戶的地址(錢包地址),類似下面所示:
0x29920e756f41F8e691aE0b12D417C19204371E91
發送到聊天室內,稍等片刻,你的賬號將收到一筆以太幣。
部署智能合約
現在帳戶里已經有了資金,可以進行部署了。
執行部署命令:
truffle migrate --network kovan
一旦部署完成,應該會看到部署成功的消息。
部署命令執行詳情:
G:\qikegu\ethereum\mydapp>truffle migrate --network kovan Compiling your contracts... =========================== > Everything is up to date, there is nothing to compile. Migrations dry-run (simulation) =============================== > Network name: 'kovan-fork' > Network id: 42 > Block gas limit: 0x7a1200 ... Starting migrations... ====================== > Network name: 'kovan' > Network id: 42 > Block gas limit: 0x7a1200 1_initial_migration.js ====================== Deploying 'Migrations' ---------------------- > transaction hash: 0x7e30b5c716afed45888a9dd2d6af7e6f52a9fade0346e8ad7d0c268de508a26a > Blocks: 2 Seconds: 9 > contract address: 0x168A7247B58786edd259502948f5Bf9449C863AD > block number: 13447029 > block timestamp: 1568294312 > account: 0x29920e756f41F8e691aE0b12D417C19204371E91 > balance: 2.993465175 > gas used: 261393 > gas price: 25 gwei > value sent: 0 ETH > total cost: 0.006534825 ETH > Saving migration to chain. > Saving artifacts ------------------------------------- > Total cost: 0.006534825 ETH 2_deploy_contracts.js ===================== Deploying 'MyContract' ---------------------- > transaction hash: 0xc1f7ec8fee1a23e3d08d0c9e9d6e15fef24feb8ba163e0071dccb1bb90cc0eca > Blocks: 0 Seconds: 0 > contract address: 0x4D3CFaF8457CEA76c0409f989f9870115B4d2d82 > block number: 13447036 > block timestamp: 1568294340 > account: 0x29920e756f41F8e691aE0b12D417C19204371E91 > balance: 2.9850534 > gas used: 294448 > gas price: 25 gwei > value sent: 0 ETH > total cost: 0.0073612 ETH > Saving migration to chain. > Saving artifacts ------------------------------------- > Total cost: 0.0073612 ETH Summary ======= > Total deployments: 2 > Final cost: 0.013896025 ETH Summary ======= > Total deployments: 2 > Final cost: 0.013896025 ETH
驗證部署
現在打開truffle控制台,與kovan測試網絡上的智能合約進行交互:
$ truffle console --network kovan
在控制台中執行:
truffle(kovan)> MyContract.deployed().then((c) => { contract = c })
然后:
truffle(kovan)> contract.get() 'myValue' truffle(kovan)> contract.set("hello world") { tx: '0x7bf63444f3a7bd70e981a7bd49228b1cf1a8c3754daf64c4c7765b8eee46bf37', receipt: { blockHash: '0xe03d0f43d85f4e41c18a90aa563ebda08899c6b9c38d0cd7779937046e2aed0c', blockNumber: 13447763, contractAddress: null, cumulativeGasUsed: 33629, from: '0x29920e756f41f8e691ae0b12d417c19204371e91', gasUsed: 33629, logs: [], logsBloom: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', root: null, status: true, to: '0x4d3cfaf8457cea76c0409f989f9870115b4d2d82', transactionHash: '0x7bf63444f3a7bd70e981a7bd49228b1cf1a8c3754daf64c4c7765b8eee46bf37', transactionIndex: 0, rawLogs: [] }, logs: [] } truffle(kovan)> contract.get() 'hello world'
可以看到智能合約已經成功部署。
以太坊(Ethereum) – truffle腳本
Truffle包含一個腳本運行器,可對以太坊網絡執行自定義腳本。
讓我們創建一個腳本並執行。
在項目根目錄下,創建script.js文件,內容如下:
module.exports = function(callback) { web3.eth.getBlock('latest').then(console.log) }
該腳本將從Kovan測試網絡獲取最新區塊的信息。
執行腳本:
truffle exec script.js --network kovan
輸出
{ author: '0x596e8221a30bfe6e7eff67fee664a01c73ba3c56',
difficulty: '340282366920938463463374607431768211454',
extraData:
'0xde830205058f5061726974792d457468657265756d86312e33362e30826c69',
gasLimit: '0x7a1200',
gasUsed: '0x5e61',
hash:
'0x225a1e0b13fd20396af60d049ce9bb94c2f3f7df06c7db260880b62c91997004',
logsBloom:
'0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
miner: '0x596e8221A30bFe6e7eFF67Fee664A01C73BA3C56',
number: 13448162,
parentHash:
'0x28d00fd7b66771130ed98de5073c7797ee293e7bee4b546793a4b79171555066',
receiptsRoot:
'0x44617b5733ee59bde159af08ffd6edae36e0964f1724c333f3d1bef0808dee15',
sealFields:
[ '0x84175e95d7',
'0xb8412ed900e67f4a72925fb3b495efb3f547411f40d26e972cc0e8b2cf26e40cf84a545e0328199d4880b79c62670129a7db12ac58234bee0866c6376b46ab99e8a200' ],
sha3Uncles:
'0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347',
signature:
'2ed900e67f4a72925fb3b495efb3f547411f40d26e972cc0e8b2cf26e40cf84a545e0328199d4880b79c62670129a7db12ac58234bee0866c6376b46ab99e8a200',
size: 797,
stateRoot:
'0xe1bbaacfb950361bec70f4ad53a2605e1ac1d2ff0bfd913fe063dc6c5f3252a0',
step: '392074711',
timestamp: 1568298844,
totalDifficulty: '4525729278306228651801195598997744985609807728',
transactions:
[ '0xf1ae41eac6b32419bc62a6cde9cab4b4ca244899a3d49b4a2461bcf94f504176' ],
transactionsRoot:
'0xf08c8097ea946f84ce9594ce73648fc0f9f683adef105a5db00c5f1f15e61c2c',
uncles: [] }
下面的代碼智能合約MyContract中,讀取value值,將script.js腳本文件中的代碼替換為:
const MyContract = artifacts.require("./MyContract.sol"); module.exports = async function(callback) { const contract = await MyContract.deployed() const value = await contract.get() console.log("Value:", value) }
執行腳本:
truffle exec script.js --network kovan
輸出
Value: hello world
以太坊(Ethereum) – 讓瀏覽器支持區塊鏈(MetaMask)
大多數web瀏覽器目前都不支持連接到區塊鏈網絡,不過可以通過安裝瀏覽器插件,來讓瀏覽器支持區塊鏈。
安裝MetaMask
我們將為Chrome瀏覽器安裝Metamask錢包插件(需FQ)。
安裝好后,確保插件的啟用按鈕打開,在瀏覽器的右上角會看到一個狐狸
圖標。
導入賬號
把錢包賬號從Ganache導入到Metamask中,這樣我們就可以連接到區塊鏈了。
打開Ganache主界面,如下圖所示,復制MNEMONIC的值:

打開Metamask,選擇通過Seed Phrase導入賬號,把復制MNEMONIC的值,粘貼到Wallet Seed,如下圖所示:

進入錢包
查看Kovan網絡,可以看到里面有一些測試以太幣余額。

現在我們的Chrome瀏覽器已經支持區塊鏈了。
以太坊(Ethereum) – 智能合約前端頁面
現在我們來開發智能合約的前端頁面,讓用戶可以通過前端頁面與智能合約交互。這個頁面的主要功能是:
- 顯示當前連接的帳戶
- 讀取智能合約中存儲的value值
- 更新智能合約中存儲的value值
頁面大概的樣子:

為開發前端頁面,需要完成下面幾項工作:
- 配置web服務器,用來部署頁面
- 創建前端的h5、js文件
配置web服務器
首先,讓我們來配置web服務器。服務器使用lite-server,安裝lite-server:
$ npm install lite-server --save-dev
項目根目錄下,創建lite-server的配置文件bs-config.json,內容如下:
{ "server": { "baseDir": [ "./src", "./build/contracts" ], "routes": { "/vendor": "./node_modules" } } }
baseDir配置告訴lite-server將./src和./build/contracts目錄作為web服務器的根目錄,所有文件都可以被訪問routes把./node_modules映射為/vendor,在引用文件時,可以使用/vendor
創建前端頁面
項目根目錄下,創建src目錄,用於存放前端頁面。
前端頁面包含2個文件:
src/index.html
src/app.js
index.html
添加index.html頁面,內容如下:
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>以太坊 DApp Demo</title> <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries --> <!-- WARNING: Respond.js doesn't work if you view the page via file:// --> <!--[if lt IE 9]> <script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script> <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script> <![endif]--> </head> <body> <h1>賬號: <span id="account"></span></h1> <hr> <div id="content"> <h2>智能合約:MyContract</b></h2> <p>獲取智能合約中的value值: <span id="value"></span></p> <h5>設置value值</h5> <form onSubmit="App.set(); return false;" role="form"> <div > <input id="newValue" type="text"></input> </div> <button type="submit" >設置</button> </form> </div> <div id="loader">正在加載...</div> </div> <!-- jQuery (necessary for Bootstrap's JavaScript plugins) --> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script> <!-- Include all compiled plugins (below), or include individual files as needed --> <script src="https://etherscan.io/jss/web3.min.js"></script> <script src="vendor/@truffle/contract/dist/truffle-contract.js"></script> <script src="app.js"></script> </body> </html>
這個文件的重點是引入了幾個js文件:
web3.min.js– web3.js庫文件,直接從https://etherscan.io/引入truffle-contract.js– truffle提供的處理智能合約的庫文件
安裝@truffle/contract
$ npm install @truffle/contract --save-dev
app.js
添加javascript腳本文件:app.js
App = { web3Provider: null, contracts: {}, account: '0x0', loading: false, contractInstance: null, init: async () => { // 加載web3 await App.loadWeb3() // 加載智能合約 await App.loadContract() // 網頁刷新 await App.render() }, // https://medium.com/metamask/https-medium-com-metamask-breaking-change-injecting-web3-7722797916a8 loadWeb3: async () => { if (typeof web3 !== 'undefined') { App.web3Provider = web3.currentProvider web3 = new Web3(web3.currentProvider) } else { window.alert("Please connect to Metamask.") } // MetaMask新版本… if (window.ethereum) { window.web3 = new Web3(ethereum) try { // 向用戶請求帳戶訪問 await ethereum.enable() // 用戶允許使用賬戶 web3.eth.sendTransaction({/* ... */ }) } catch (error) { // 用戶拒絕使用賬戶 } } // MetaMask老版本… else if (window.web3) { App.web3Provider = web3.currentProvider window.web3 = new Web3(web3.currentProvider) // 無需向用戶請求,可以直接使用賬號 web3.eth.sendTransaction({/* ... */ }) } // 沒有安裝以太坊錢包插件(MetaMask)... else { console.log('需要安裝以太坊錢包插件(例如MetaMask)才能使用!') } }, loadContract: async () => { const contract = await $.getJSON('MyContract.json') App.contracts.MyContract = TruffleContract(contract) App.contracts.MyContract.setProvider(App.web3Provider) }, render: async () => { // 如果正在加載,直接返回,避免重復操作 if (App.loading) { return } // 更新app加載狀態 App.setLoading(true) // 設置當前區塊鏈帳戶 const accounts = await ethereum.enable() App.account = accounts[0] $('#account').html(App.account) // 加載智能合約 const contract = await App.contracts.MyContract.deployed() App.contractInstance = contract const value = await App.contractInstance.get() $('#value').html(value) App.setLoading(false) }, set: async () => { App.setLoading(true) const newValue = $('#newValue').val() await App.contractInstance.set(newValue, {from: App.account}) window.alert('更新成功,頁面值不會馬上更新,等待幾秒后多刷新幾次。') App.setLoading(false) }, setLoading: (boolean) => { App.loading = boolean const loader = $('#loader') const content = $('#content') if (boolean) { loader.show() content.hide() } else { loader.hide() content.show() } } } $(document).ready(function () { App.init() });
在上面的代碼中:
loadWeb3()函數添加了用Metamask將web瀏覽器連接到區塊鏈所需的配置。這是直接從Metamask的配置規范中復制粘貼的,如函數上面代碼注釋中的url所示。loadContract()函數使用TruffleContract庫創建智能合約的javascript對象,可以用於調用智能合約中的函數。render()函數設置頁面內容,包括帳戶及智能合約的value值。
現在啟動服務器:
$ npm run dev
然后使用安裝了MetaMask插件的Chrome瀏覽器,打開網址:http://localhost:3000,就可以查看前端頁面,與區塊鏈上的智能合約進行交互。
以太坊(Ethereum) – truffle腳本
Truffle包含一個腳本運行器,可對以太坊網絡執行自定義腳本。
讓我們創建一個腳本並執行。
在項目根目錄下,創建script.js文件,內容如下:
該腳本將從Kovan測試網絡獲取最新區塊的信息。
執行腳本:
輸出:
下面的代碼智能合約MyContract中,讀取value值,將script.js腳本文件中的代碼替換為:
執行腳本:
輸出:
腳本運行器是一個非常有用的功能。
Doc navigation
類似Java中JUnit單元測試工具,Trfuffle test可以幫助我們對智能合約項目進行白盒測試。
對於區塊鏈項目,測試顯得尤其重要,因為部署合約、遷移合約的成本都是相當高的,都要消耗Gas。
編寫測試代碼
現在讓我們對前面章節中創建的智能合約,編寫一些測試代碼。整個測試過程模擬對智能合約MyContract獲取value值、設置value值的過程。
先確保MyContract已經正確部署到Ganache本地區塊鏈網絡中。測試中將會用到Mocha測試框架,與Chai斷言庫,但Truffle已經集成了這些庫。
測試代碼用JavaScript編寫,模擬與智能合約的交互,就像使用truffle console所做的那樣。
在項目根目錄下的test目錄中,添加測試腳本文件: MyContract.js
MyContract.js中的測試代碼:
// 首先,`require`合約並將其分配給一個變量`MyContract` const MyContract = artifacts.require('./MyContract.sol'); // 調用“contract”函數,並在回調函數中編寫所有測試 // 回調函數提供一個“accounts”變量,表示本地區塊鏈上的所有帳戶。 contract('MyContract', (accounts) => { // 第1個測試:調用get()函數,檢查返回值,測試合約中value初始值是否是: 'myValue' it('initializes with the correct value', async () => { // 獲取合約實例 const myContract = await MyContract.deployed() const value = await myContract.get() // 使用斷言測試value的值 assert.equal(value, 'myValue') }) // 第2個測試: 調用set()函數來設置value值,然后調用get()函數來確保更新了值 it('can update the value', async () => { const myContract = await MyContract.deployed() myContract.set('New Value'); const value = await myContract.get() assert.equal(value, 'New Value') }) })
代碼說明,請見注釋。
運行測試腳本
執行命令行運行測試:
$ truffle test
測試詳情:
G:\qikegu\ethereum\mydapp>truffle test Using network 'development'. Compiling your contracts... =========================== > Everything is up to date, there is nothing to compile. Contract: MyContract √ initializes with the correct value (76ms) √ can update the value (78ms) 2 passing (188ms)
以太坊(Ethereum) – 連接公鏈
本篇介紹如何將Truffle項目連接到公共區塊鏈網絡。
到目前為止,我們連接的都是在本地區塊鏈(Ganache),接下來將連接以太坊公鏈。
以太坊公鏈除了主網,還有多個測試網絡。主網(Mainnet)是正式的以太坊網絡,里面的以太幣是真正有價值的,測試網絡中的以太幣沒有價值,只用於測試。
我們最終目標是連接到主網,但先連接到測試網絡Kovan,雖然本地區塊鏈網絡(Ganache)也能測試,但與公鏈還是有區別的。
連接到公鏈的步驟如下:
- 設置錢包來管理公鏈帳戶
- 連接到以太坊節點
- 更新項目設置
- 訪問以太坊節點
設置錢包
首先需要設置一個錢包,來管理我們的公鏈帳戶。
簡單起見,可以借用Ganache本地區塊鏈錢包,由於區塊鏈的工作原理,這個錢包在公共區塊鏈和本地區塊鏈上都是有效的。
打開Ganache,主界面上可以看到一個名為“MNEMONIC”的部分:

這是一個種子短語,用於構建由Ganache管理的錢包。我們可以使用這個種子短語加密重建錢包,來連接到公鏈。
復制這個值,保存到一個秘密文件,MNEMONIC是一個秘密值,需要保密。在項目根目錄中創建一個.env文件,保存MNEMONIC值,如下所示:
MNEMONIC="你的mnemonic"
連接以太坊節點
現在已經創建了錢包,下一步需要訪問Ethereum節點,以便連接到公共區塊鏈網絡。
有幾種方法可以做到這一點,可以使用Geth或Parity運行自己的Ethereum節點。但這需要從區塊鏈下載大量數據並保持同步,很麻煩。
比較方便的方法是,使用Infura訪問Ethereum節點。Infura是一個免費提供Ethereum節點的服務。
在Infura上注冊賬號,創建項目,在項目詳情頁上可以查看API KEY:

使用API KEY,就可以訪問以太坊網絡節點。
在.env文件中添加Infura api key的配置:
INFURA_API_KEY="https://kovan.infura.io/v3/543526cd4d3846acbc3826484e934564" MNEMONIC="你的mnemonic"
更新項目設置
接下來使用MNEMONIC與INFURA_API_KEY,更新項目的網絡配置,以便連接到公共區塊鏈網絡。
修改truffle-config.js文件:
// 導入dotenv庫創用於讀取`.env`文件中的設置 require('dotenv').config(); // 導入truffle-hdwallet-provider庫重建錢包 const HDWalletProvider = require('truffle-hdwallet-provider'); module.exports = { networks: { development: { host: "127.0.0.1", // Localhost (default: none) port: 7545, // Standard Ethereum port (default: none) network_id: "*", // Any network (default: none) }, // Useful for deploying to a public network. // NB: It's important to wrap the provider as a function. kovan: { provider: () => new HDWalletProvider( process.env.MNEMONIC, process.env.INFURA_API_KEY ), gas: 5000000, gasPrice: 25000000000, network_id: 42 }, }, solc: { optimizer: { enabled: true, runs: 200 } } }
可以看到,我們使用了.env配置文件中的MNEMONIC與INFURA_API_KEY配置了kovan網絡。
由於用到了dotenv與truffle-hdwallet-provider這2個庫,我們需要先安裝:
切換到項目目錄,執行以下命令
npm install dotenv --save-dev
npm install truffle-hdwallet-provider --save-dev
注意 安裝truffle-hdwallet-provider時,如果出現node-gyp相關的錯誤,可參考這里解決。
訪問以太坊節點
使用truffle console連接到公共區塊鏈網絡:
$ truffle console --network kovan
要驗證連接,可以從區塊鏈中讀取一些數據,獲取一些關於最新區塊的信息,在控制台上執行:
web3.eth.getBlock('latest').then(console.log)
輸出
{ author: '0x03801efb0efe2a25ede5dd3a003ae880c0292e4d',
difficulty: '340282366920938463463374607431768211454',
extraData:
'0xde830206028f5061726974792d457468657265756d86312e33362e30826c69',
gasLimit: '0x7a1200',
gasUsed: '0x17d23',
hash:
'0xc7390c4f492c8c1da60608135fc9e05930123b645b39f221cba33d8b3c577b2a',
logsBloom:
'0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000080000000000000000000100000008000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400800000000000010000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009000000008000000',
receiptsRoot:
'0x3d05bb2ed4fcc90234eea6d840e7d0e3ce7f598a15e5314536b17bcd11c78b5b',
sealFields:
[ '0x84175e8801',
'0xb84155a8cdb108dccec1d314124058fa6f22e7400ee200db0a94b7b165e4c3454c1818cc05f815cb7ce48f7a88b8401515740311a3566d9cf079428d506a6daca50101' ],
sha3Uncles:
'0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347',
signature:
'55a8cdb108dccec1d314124058fa6f22e7400ee200db0a94b7b165e4c3454c1818cc05f815cb7ce48f7a88b8401515740311a3566d9cf079428d506a6daca50101',
size: 877,
stateRoot:
'0x03af5adce52a81ce5d332cddb9955e344214bff00859b78868116e1e839efdf7',
step: '392071169',
timestamp: 1568284676,
totalDifficulty: '4524524338444961608702071789512829094373049115',
transactions:
[ '0xded7fed0842fd65ec808bc3652ec4175bc190acc11345c49c44b1fb5d954610f',
'0x7e9112a46fa3c07aad813ea86355b15eebb44023c040d198ee7d15d379bbc2be' ],
transactionsRoot:
'0x0dd10d90686dda2684bd0ba70d1c9e1d9a5302c30ca75eb2c5b07a7b6e4498b9',
uncles: [] }
可以看到,已經成功連接到了公鏈。
以太坊(Ethereum) – 部署智能合約到公鏈
現在,我們將智能合約部署到公鏈。步驟如下:
- 部署需要消耗Gas,獲取測試以太幣用於部署
- 部署智能合約
- 驗證部署
獲取測試以太幣
部署需要消耗Gas,Gas需要支付以太幣,我們部署到的是公鏈測試網Kovan,網絡中的以太幣沒有市場價值。
可以從Kovan faucet Gitter聊天室獲取測試用的偽以太幣。只需把錢包地址發送出去,約5分鍾內,有人會給你發測試用的偽以太幣。
打開Ganache並復制列表中第一個帳戶的地址(錢包地址),類似下面所示:
0x29920e756f41F8e691aE0b12D417C19204371E91
發送到聊天室內,稍等片刻,你的賬號將收到一筆以太幣。
部署智能合約
現在帳戶里已經有了資金,可以進行部署了。
執行部署命令:
truffle migrate --network kovan
一旦部署完成,應該會看到部署成功的消息。
部署命令執行詳情:
G:\qikegu\ethereum\mydapp>truffle migrate --network kovan Compiling your contracts... =========================== > Everything is up to date, there is nothing to compile. Migrations dry-run (simulation) =============================== > Network name: 'kovan-fork' > Network id: 42 > Block gas limit: 0x7a1200 ... Starting migrations... ====================== > Network name: 'kovan' > Network id: 42 > Block gas limit: 0x7a1200 1_initial_migration.js ====================== Deploying 'Migrations' ---------------------- > transaction hash: 0x7e30b5c716afed45888a9dd2d6af7e6f52a9fade0346e8ad7d0c268de508a26a > Blocks: 2 Seconds: 9 > contract address: 0x168A7247B58786edd259502948f5Bf9449C863AD > block number: 13447029 > block timestamp: 1568294312 > account: 0x29920e756f41F8e691aE0b12D417C19204371E91 > balance: 2.993465175 > gas used: 261393 > gas price: 25 gwei > value sent: 0 ETH > total cost: 0.006534825 ETH > Saving migration to chain. > Saving artifacts ------------------------------------- > Total cost: 0.006534825 ETH 2_deploy_contracts.js ===================== Deploying 'MyContract' ---------------------- > transaction hash: 0xc1f7ec8fee1a23e3d08d0c9e9d6e15fef24feb8ba163e0071dccb1bb90cc0eca > Blocks: 0 Seconds: 0 > contract address: 0x4D3CFaF8457CEA76c0409f989f9870115B4d2d82 > block number: 13447036 > block timestamp: 1568294340 > account: 0x29920e756f41F8e691aE0b12D417C19204371E91 > balance: 2.9850534 > gas used: 294448 > gas price: 25 gwei > value sent: 0 ETH > total cost: 0.0073612 ETH > Saving migration to chain. > Saving artifacts ------------------------------------- > Total cost: 0.0073612 ETH Summary ======= > Total deployments: 2 > Final cost: 0.013896025 ETH Summary ======= > Total deployments: 2 > Final cost: 0.013896025 ETH
驗證部署
現在打開truffle控制台,與kovan測試網絡上的智能合約進行交互:
$ truffle console --network kovan
在控制台中執行:
truffle(kovan)> MyContract.deployed().then((c) => { contract = c })
然后:
truffle(kovan)> contract.get() 'myValue' truffle(kovan)> contract.set("hello world") { tx: '0x7bf63444f3a7bd70e981a7bd49228b1cf1a8c3754daf64c4c7765b8eee46bf37', receipt: { blockHash: '0xe03d0f43d85f4e41c18a90aa563ebda08899c6b9c38d0cd7779937046e2aed0c', blockNumber: 13447763, contractAddress: null, cumulativeGasUsed: 33629, from: '0x29920e756f41f8e691ae0b12d417c19204371e91', gasUsed: 33629, logs: [], logsBloom: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', root: null, status: true, to: '0x4d3cfaf8457cea76c0409f989f9870115b4d2d82', transactionHash: '0x7bf63444f3a7bd70e981a7bd49228b1cf1a8c3754daf64c4c7765b8eee46bf37', transactionIndex: 0, rawLogs: [] }, logs: [] } truffle(kovan)> contract.get() 'hello world'
可以看到智能合約已經成功部署。
以太坊(Ethereum) – truffle腳本
Truffle包含一個腳本運行器,可對以太坊網絡執行自定義腳本。
讓我們創建一個腳本並執行。
在項目根目錄下,創建script.js文件,內容如下:
module.exports = function(callback) { web3.eth.getBlock('latest').then(console.log) }
該腳本將從Kovan測試網絡獲取最新區塊的信息。
執行腳本:
truffle exec script.js --network kovan
輸出
{ author: '0x596e8221a30bfe6e7eff67fee664a01c73ba3c56',
difficulty: '340282366920938463463374607431768211454',
extraData:
'0xde830205058f5061726974792d457468657265756d86312e33362e30826c69',
gasLimit: '0x7a1200',
gasUsed: '0x5e61',
hash:
'0x225a1e0b13fd20396af60d049ce9bb94c2f3f7df06c7db260880b62c91997004',
logsBloom:
'0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
miner: '0x596e8221A30bFe6e7eFF67Fee664A01C73BA3C56',
number: 13448162,
parentHash:
'0x28d00fd7b66771130ed98de5073c7797ee293e7bee4b546793a4b79171555066',
receiptsRoot:
'0x44617b5733ee59bde159af08ffd6edae36e0964f1724c333f3d1bef0808dee15',
sealFields:
[ '0x84175e95d7',
'0xb8412ed900e67f4a72925fb3b495efb3f547411f40d26e972cc0e8b2cf26e40cf84a545e0328199d4880b79c62670129a7db12ac58234bee0866c6376b46ab99e8a200' ],
sha3Uncles:
'0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347',
signature:
'2ed900e67f4a72925fb3b495efb3f547411f40d26e972cc0e8b2cf26e40cf84a545e0328199d4880b79c62670129a7db12ac58234bee0866c6376b46ab99e8a200',
size: 797,
stateRoot:
'0xe1bbaacfb950361bec70f4ad53a2605e1ac1d2ff0bfd913fe063dc6c5f3252a0',
step: '392074711',
timestamp: 1568298844,
totalDifficulty: '4525729278306228651801195598997744985609807728',
transactions:
[ '0xf1ae41eac6b32419bc62a6cde9cab4b4ca244899a3d49b4a2461bcf94f504176' ],
transactionsRoot:
'0xf08c8097ea946f84ce9594ce73648fc0f9f683adef105a5db00c5f1f15e61c2c',
uncles: [] }
下面的代碼智能合約MyContract中,讀取value值,將script.js腳本文件中的代碼替換為:
const MyContract = artifacts.require("./MyContract.sol"); module.exports = async function(callback) { const contract = await MyContract.deployed() const value = await contract.get() console.log("Value:", value) }
執行腳本:
truffle exec script.js --network kovan
輸出
Value: hello world
以太坊(Ethereum) – 讓瀏覽器支持區塊鏈(MetaMask)
大多數web瀏覽器目前都不支持連接到區塊鏈網絡,不過可以通過安裝瀏覽器插件,來讓瀏覽器支持區塊鏈。
安裝MetaMask
我們將為Chrome瀏覽器安裝Metamask錢包插件(需FQ)。
安裝好后,確保插件的啟用按鈕打開,在瀏覽器的右上角會看到一個狐狸
圖標。
導入賬號
把錢包賬號從Ganache導入到Metamask中,這樣我們就可以連接到區塊鏈了。
打開Ganache主界面,如下圖所示,復制MNEMONIC的值:

打開Metamask,選擇通過Seed Phrase導入賬號,把復制MNEMONIC的值,粘貼到Wallet Seed,如下圖所示:

進入錢包
查看Kovan網絡,可以看到里面有一些測試以太幣余額。

現在我們的Chrome瀏覽器已經支持區塊鏈了。
以太坊(Ethereum) – 智能合約前端頁面
現在我們來開發智能合約的前端頁面,讓用戶可以通過前端頁面與智能合約交互。這個頁面的主要功能是:
- 顯示當前連接的帳戶
- 讀取智能合約中存儲的value值
- 更新智能合約中存儲的value值
頁面大概的樣子:

為開發前端頁面,需要完成下面幾項工作:
- 配置web服務器,用來部署頁面
- 創建前端的h5、js文件
配置web服務器
首先,讓我們來配置web服務器。服務器使用lite-server,安裝lite-server:
$ npm install lite-server --save-dev
項目根目錄下,創建lite-server的配置文件bs-config.json,內容如下:
{ "server": { "baseDir": [ "./src", "./build/contracts" ], "routes": { "/vendor": "./node_modules" } } }
baseDir配置告訴lite-server將./src和./build/contracts目錄作為web服務器的根目錄,所有文件都可以被訪問routes把./node_modules映射為/vendor,在引用文件時,可以使用/vendor
創建前端頁面
項目根目錄下,創建src目錄,用於存放前端頁面。
前端頁面包含2個文件:
src/index.html
src/app.js
index.html
添加index.html頁面,內容如下:
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>以太坊 DApp Demo</title> <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries --> <!-- WARNING: Respond.js doesn't work if you view the page via file:// --> <!--[if lt IE 9]> <script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script> <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script> <![endif]--> </head> <body> <h1>賬號: <span id="account"></span></h1> <hr> <div id="content"> <h2>智能合約:MyContract</b></h2> <p>獲取智能合約中的value值: <span id="value"></span></p> <h5>設置value值</h5> <form onSubmit="App.set(); return false;" role="form"> <div > <input id="newValue" type="text"></input> </div> <button type="submit" >設置</button> </form> </div> <div id="loader">正在加載...</div> </div> <!-- jQuery (necessary for Bootstrap's JavaScript plugins) --> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script> <!-- Include all compiled plugins (below), or include individual files as needed --> <script src="https://etherscan.io/jss/web3.min.js"></script> <script src="vendor/@truffle/contract/dist/truffle-contract.js"></script> <script src="app.js"></script> </body> </html>
這個文件的重點是引入了幾個js文件:
web3.min.js– web3.js庫文件,直接從https://etherscan.io/引入truffle-contract.js– truffle提供的處理智能合約的庫文件
安裝@truffle/contract
$ npm install @truffle/contract --save-dev
app.js
添加javascript腳本文件:app.js
App = { web3Provider: null, contracts: {}, account: '0x0', loading: false, contractInstance: null, init: async () => { // 加載web3 await App.loadWeb3() // 加載智能合約 await App.loadContract() // 網頁刷新 await App.render() }, // https://medium.com/metamask/https-medium-com-metamask-breaking-change-injecting-web3-7722797916a8 loadWeb3: async () => { if (typeof web3 !== 'undefined') { App.web3Provider = web3.currentProvider web3 = new Web3(web3.currentProvider) } else { window.alert("Please connect to Metamask.") } // MetaMask新版本… if (window.ethereum) { window.web3 = new Web3(ethereum) try { // 向用戶請求帳戶訪問 await ethereum.enable() // 用戶允許使用賬戶 web3.eth.sendTransaction({/* ... */ }) } catch (error) { // 用戶拒絕使用賬戶 } } // MetaMask老版本… else if (window.web3) { App.web3Provider = web3.currentProvider window.web3 = new Web3(web3.currentProvider) // 無需向用戶請求,可以直接使用賬號 web3.eth.sendTransaction({/* ... */ }) } // 沒有安裝以太坊錢包插件(MetaMask)... else { console.log('需要安裝以太坊錢包插件(例如MetaMask)才能使用!') } }, loadContract: async () => { const contract = await $.getJSON('MyContract.json') App.contracts.MyContract = TruffleContract(contract) App.contracts.MyContract.setProvider(App.web3Provider) }, render: async () => { // 如果正在加載,直接返回,避免重復操作 if (App.loading) { return } // 更新app加載狀態 App.setLoading(true) // 設置當前區塊鏈帳戶 const accounts = await ethereum.enable() App.account = accounts[0] $('#account').html(App.account) // 加載智能合約 const contract = await App.contracts.MyContract.deployed() App.contractInstance = contract const value = await App.contractInstance.get() $('#value').html(value) App.setLoading(false) }, set: async () => { App.setLoading(true) const newValue = $('#newValue').val() await App.contractInstance.set(newValue, {from: App.account}) window.alert('更新成功,頁面值不會馬上更新,等待幾秒后多刷新幾次。') App.setLoading(false) }, setLoading: (boolean) => { App.loading = boolean const loader = $('#loader') const content = $('#content') if (boolean) { loader.show() content.hide() } else { loader.hide() content.show() } } } $(document).ready(function () { App.init() });
在上面的代碼中:
loadWeb3()函數添加了用Metamask將web瀏覽器連接到區塊鏈所需的配置。這是直接從Metamask的配置規范中復制粘貼的,如函數上面代碼注釋中的url所示。loadContract()函數使用TruffleContract庫創建智能合約的javascript對象,可以用於調用智能合約中的函數。render()函數設置頁面內容,包括帳戶及智能合約的value值。
現在啟動服務器:
$ npm run dev
然后使用安裝了MetaMask插件的Chrome瀏覽器,打開網址:http://localhost:3000,就可以查看前端頁面,與區塊鏈上的智能合約進行交互。
以太坊(Ethereum) – truffle腳本
Truffle包含一個腳本運行器,可對以太坊網絡執行自定義腳本。
讓我們創建一個腳本並執行。
在項目根目錄下,創建script.js文件,內容如下:
該腳本將從Kovan測試網絡獲取最新區塊的信息。
執行腳本:
輸出:
下面的代碼智能合約MyContract中,讀取value值,將script.js腳本文件中的代碼替換為:
執行腳本:
輸出:
腳本運行器是一個非常有用的功能。
