利用工具加速Dapp建置和測試

NIC Lin
NIC Lin
Jan 3, 2017 · 10 min read

藉由Testrpc和Truffle加速Ethereum Dapp的開發

快速介紹:
開發Dapp你需要有鏈(你的資料庫)和一個互動的介面(網頁、手機app等等):
1. 鏈的部分有提供各種不同 client software(Geth、Parity等等),下載後就可以對鏈進行操作,不過麻煩的是所有過程(挖礦、建立帳戶、帳戶間轉錢)都要親自動手做。
如果需要測試的智能合約非常複雜,那就會花很多時間成本在這些瑣事上面,所以這裡首先介紹的Testrpc便是用來加速這個過程的。
Testrpc提供一個快速方便的測試環境:每次執行它都會幫你創建十組帳號且裡面都有充足的ether讓你做測試、挖礦是自動的(每個transaction執行都是即時的),但缺點是它的鏈的資料是暫存在記憶體而不是寫在硬碟裡,所以Testrpc關掉之後,所有鏈的資料(帳戶餘額、合約等)都會消失,因此比較適合用來快速測試你的智能合約的功能。

2. Truffle則是自動化從合約的編譯(truffle compile)到部署合約(truffle deploy)再到app建置(truffle build)的過程。其中不含鏈的建置和操作,所以要搭配Testrpc(或用client software自建一個節點並開放rpc)才能完成。

介紹完後,開始安裝truffle和testrpc:

sudo npm install -g ethreumjs-testrpc
sudo npm install -g truffle

接著先跑起testrpc:

testrpc

不額外指定的話每次都會建立新的十組帳戶,每組裡面都會有一百ether。其中HD Wallet欄位裡的Mnemonic如果之後需要產生同樣一組帳戶,可以記下來。每次都會產生不同的帳戶(對應到不同的Mnemonic),但如果透過 -m 來指定Mnemonic,即會產生其對應的帳戶。

testrpc -m "truck sand amateur oak trigger soft helmet jump explain resource exchange tree"

Listening on localhost:8545 表示testrpc的rpc開的port為8545。
跑起testrpc後,就可以開啟一個truffle專案了。

mkdir test123
cd test123
truffle init

初始化會有一個Metacoin的範例,部署這個合約的人會有Meta幣,可以利用合約裡的sendCoin函式將Meta幣轉給其他人。
我們直接使用這個範例合約。

首先要先編譯合約:

truffle compile

sol合約會存在contracts資料夾裡,truffle要求合約名稱和檔案名稱要一致。
編譯完後的執行檔(.js檔)會放在/build/contracts資料夾裡。

接下來是部署合約:

truffle migrate

migrate會執行migration資料夾裡的js檔,js檔名開頭必須是數字(truffle會按照這順序執行,數字後的名稱可任意指定)。truffle要求第一個執行的必須是部署一個Migrations合約(如果有init,contracts資料夾裡會有一個Migrations.sol)才能開始migrate。
每個migration的js檔裡格式如下,會有一個deployer參數:

module.exports = function(deployer){
deployer.deploy(A, arg1);
deployer.deploy(B);
};

如此會照順序部署合約A及B,deploy的第一個參數為合約名稱,如果合約constructor有參數則加在其後。
當合約之間部署有相依性如B合約的constructor會用到A合約部署的地址:

module.exports = function(deployer){
deployer.deploy(A).then(function(){
return deployer.deploy(B, A.address);
});
};

或是建立一個新的A合約,然後在已部署的B合約裡呼叫setA函式並傳入新的A合約地址來更新資料:

deployer.then(function() {
// Create a new version of A
return A.new();
}).then(function(instance) {
// Set the new instance of A's address on B.
var b = B.deployed();
return b.setA(instance.address);
});

如果有library,則需要將合約與library建立link:

// Deploy library LibA, then link LibA to contract B
deployer.deploy(LibA);
deployer.link(LibA, B);

// Link LibA to many contracts
deployer.link(LibA, [B, C, D]);

或是使用autolink(),前提是library合約都必須已經部署:

// Assume A depends on a LibB and LibC
deployer.deploy([LibB, LibC]);
deployer.autolink(A);

如果有不同條鏈的話,可以使用network參數來判斷:

module.exports = function(deployer, network) {
if (network == "test_env") {
deployer.deploy(A);
deployer.deploy(B);
}
else if(network == "testnet"){
deployer.deploy(C);
}
else {
deployer.exec("../path/to/file/live_demo.js)
}
}

deployer.exec()會執行相對於migration檔的路徑的js檔,如果固定要在部署過程中做一些小測試會方便許多。
network的設定待會會做說明。

註:執行過的migration檔不會再執行,如果有更改過已經執行過的migration檔,要在migrate指令加上--reset,它會重新部署一次:

truffle migrate --reset

部署完後,可以進入console來操作:

truffle console

可以直接使用合約名稱去操作:

truffle console
>Metacoin.deployed().address
‘0x4c9fd534add127c89886788c96e246abb570fc12’

最後再build起來,然後用serve來跑起build完的app:

truffle build
truffle serve

執行serve後便可在localhost:8080看到跑起來的app

serve預設port是8080,可以用-p來指定。

最後是設定檔 truffle.js,有init的話會如下:

module.exports = {
build: {
"index.html": "index.html",
"app.js": [
"javascripts/app.js"
],
"app.css": [
"stylesheets/app.css"
],
"images/": "images/"
},
rpc: {
host: "localhost",
port: 8545
}
};

如果需要區分不同鏈的話,在其中加入networks設定值:

networks: {   
"live": {
network_id: 1, // Ethereum public network
// optional config values
// host - defaults to "localhost"
// port - defaults to 8545
// gas
// gasPrice
// from
},
"testnet": {
network_id: 2, // Official Ethereum test network
host: "61.66.218.xxx",
port: 8000
},
"private": {
network_id: 5566, // custom private network
host: "localhost",
port: 8001
},
"test_env": {
network_id: "default"
}
}

不同鏈給定不同名稱來區分,裡面可以指定連接到的rpc相關設定,都不指定就是使用rpc預設的localhost:8545,其中from是指定部署時要使用哪個帳戶當部署者。
network_id可以有一個是設為default,如果network名稱沒指定或不在設定值裡面,那就會連到default的那個,一般用來和Testrpc搭配使用。

要注意的是,要能連接到指定的鏈,你必須確定對應的rpc有開放。

指令如console、migrate、serve及exec都可加入--network選項來指定執行在哪條鏈上:

truffle migrate --network "testnet"

最後介紹目前還在開發階段的Metamask

在開發Dapp時,可能會遇到使用者私鑰管理的問題。如果Dapp是以網頁的形式呈現,意味使用者把私鑰交給開發者存在伺服器,透過伺服器登入來做交易的操作;如果是以app的形式呈現,則使用者便可以在自己的裝置上管理自己的私鑰,自己製作交易並簽名。

現在許多Dapp仍以網頁形式來運作,Metamask或許是一個暫時可用的解法。
1. 它將使用者私鑰儲存在本地端(瀏覽器),可以在本地端製作交易
2. 它可以選擇連接到Main net、Testnet或是自己設定rpc位址,前兩者透過Infura提供rpc服務
Metamask目前只能透過Chrome plugin來安裝。

首先,可以選擇創立新帳戶(CREATE NEW VAULT)或使用Mnemonic來使用同一組帳戶(RESTORE EXISTING VAULT):

左上方可選擇要連接的是Main net、tesenet或是自己設定rpc位址:

右上方可以選擇切換帳戶:

BUY會連接到Coinbase購買ether(但前提是要連到Main net)、SEND可以製作交易

不過安全性(XSS或是任何能取得瀏覽器暫存的人)是使用上需要考量的一個重要因素。

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store