這里寫目錄標題
- Truffle
- Truffle 簡介
- Truffle 的客戶端
- 安裝Truffle
- 創建專案
- Migration
- artifacts.require()
- exports 的函式
- deployer 物件
- 更新 migration 檔案
- 更新 truffle 組態檔
- 創建賬戶(可用 metamask 上賬戶轉幣)
- 部署
- 新建 JavaScript 檔案 app/scripts/index.js
Truffle
Truffle 簡介
truffle unbox webpack 一條命令由于要下載眾多需要的模塊,大概耗時 10
分鐘左右,所以我們先來了解一下 Truffle,
Truffle 是目前最流行的以太坊 DApp 開發框架,(按照官網說法)是一個世
界級的開發環境和測驗框架,也是所有使用了 EVM 的區塊鏈的資產管理通道,它基于 JavaScript,致力于讓以太坊上的開發變得簡單,
Truffle 有以下功能:
? 內置的智能合約編譯,鏈接,部署和二進制檔案的管理,
? 合約自動測驗,方便快速開發,
? 腳本化的、可擴展的部署與發布框架,
? 可部署到任意數量公網或私網的網路環境管理功能
? 使用 EthPM 和 NPM 提供的包管理,使用 ERC190 標準,
? 與合約直接通信的直接互動控制臺(寫完合約就可以命令列里驗證了),
? 可配的構建流程,支持緊密集成,
? 在 Truffle 環境里支持執行外部的腳本,
Truffle 的客戶端
我們之后寫的智能合約必須要部署到鏈上進行測驗,所以 truffle 構建的
DApp 也必須選擇一條鏈來進行部署,我們可以選擇部署到一些公共的測驗鏈比如 Rinkeby 或者 Ropsten 上,缺點是部署和測驗時間比較長,而且需要花費一定的時間賺取假代幣防止 out of gas,當然,對于 DApp 發布的正規流程,staging(模擬環境)還是應該用測驗公鏈的,
還有一種方式就是部署到私鏈上,這在開發階段是通常的選擇,Truffle 官方
推薦使用以下兩種客戶端:
? Ganache
? truffle develop
而 truffle develop 是 truffle 內置的客戶端,跟命令列版本的 Ganache 基本
類似,在 truffle 目錄下 bash 輸入:
>truffle develop
即可開啟客戶端,和 ganache 一樣,它也會給我們自動生成 10 個賬戶,
唯一要注意的是在 truffle develop 里執行 truffle 命令的時候需要省略前面的
“truffle”,比如“truffle compile”只需要敲“compile”就可以了
安裝Truffle
啟動 geth,然后我們來安裝 truffle,truffle 是一個 dapp 的開發框架,它
可以使得 dapp 的構建和管理非常容易,
你可以像這樣使用 npm 安裝 truffle: >npm install -g truffle
然后我們創建一個空目錄,在下面創建 truffle 專案:
>mkdir simple_voting_by_truffle_dapp
>cd simple_voting_by_truffle_dapp
>npm install -g webpack
>truffle unbox webpack
truffle init: 在當前目錄初始化一個新的 truffle 空專案(專案檔案只有
truffle-config.js 和 truffle.js;contracts 目錄中只有 Migrations.sol;migrations目錄中只有 1_initial_migration.js)
truffle unbox: 直接下載一個 truffle box,即一個預先構建好的 truffle 專案;
unbox 的程序相對會長一點,完成之后應該看到這樣的提示:

這里的 webpack 就是一個基于 webpack 構建流程的官方專案框架(truffle
box),更多 truffle box 參見 https://truffleframework.com/boxes
創建專案
初始化一個 truffle 專案時,它會創建運行一個完整 dapp 所有必要的檔案
和目錄,我們直接下載 webpack 這個 truffle box,它里面的目錄也是類似的:
>ls
README.md contracts node_modules test
webpack.config.js truffle.js app migrations
package.json
>ls app/
index.html javascripts stylesheets
>ls contracts/
ConvertLib.sol MetaCoin.sol Migrations.sol
>ls migrations/
1_initial_migration.js 2_deploy_contracts.js
? app/ - 你的應用檔案運行的默認目錄,這里面包括推薦的 javascript 文
件和 css 樣式檔案目錄,但你可以完全域定如何使用這些目錄,
? contract/ - Truffle 默認的合約檔案存放目錄, ? migrations/ - 部署腳本檔案的存放目錄
? test/ - 用來測驗應用和合約的測驗檔案目錄
? truffle.js - Truffle 的組態檔
truffle 也會創建一個你可以快速上手的示例應用,你可以放心地洗掉專案下面 contracts 目錄的 ConvertLib.sol和 MetaCoin.sol 檔案,
>rm contracts/ConvertLib.sol contracts/MetaCoin.sol
此外,在你的專案目錄下查找一個叫做 truffle.js 的組態檔,它里面包含
了一個用于開發網路的配置,將埠號從 7545 改為 8545,因為我們的私鏈及ganache 默認都會在該埠運行,
Migration
migration 的概念
理解 migrations(遷移)目錄的內容非常重要,這些遷移檔案用于將合約
部署到區塊鏈上,
之前的專案中通過在 node 控制臺中調VotingContract.new 將投票合約部署到區塊鏈上,以后,我們再也不需要這么做了,truffle 將會部署和跟蹤所有的部署,
Migrations(遷移)是 JavaScript 檔案,這些檔案負責暫存我們的部署任務,并且假定部署需求會隨著時間推移而改變,隨著專案的發展,我們應該創建新的遷移腳本,來改變鏈上的合約狀態,所有運行過的 migration 歷史記錄,都會通過特殊的遷移合約記錄在鏈上,
第一個遷移 1_initial_migration.js 向區塊鏈部署了一個叫做 Migrations
的合約,并用于存盤你已經部署的最新合約,每次你運行 migration 時,truffle 會向區塊鏈查詢獲取最新已部署好的合約,然后部署尚未部署的任何合約,
然后它會更新 Migrations 合約中的 last_completed_migration 欄位指向最新部署的合約,你可以簡單地把它當成是一個資料庫表,里面有一列
last_completed_migration ,該列總是保持最新狀態,
migration 檔案的命名有特殊要求:前綴是一個數字(必需),用來標記遷
移是否運行成功;后綴是一個描述詞匯,只是單純為了提高可讀性,方便理解,
artifacts.require()
在腳本的開始,我們用 artifacts.require() 方法告訴 truffle 想要進行部署遷
移的合約,這跟 node 里的 require 很類似,不過需要注意,最新的官方檔案告誡,應該傳入定義的合約名稱,而不要給檔案名稱——因為一個.sol 檔案中可能包含了多個 contract,
exports 的函式
migration js 里的 exports 的函式,需要接收一個 deployer 物件作為第一個
引數,這個物件在部署發布的程序中,主要是用來提供清晰的語法支持,同時提供一些通用的合約部署職責,比如保存部署的檔案以備稍后使用,
deployer 物件
deployer 物件是用來暫存(stage)部署任務的主要操作介面,
像所有其它在 Truffle 中的代碼一樣,Truffle 提供了我們自己代碼的合約抽
象層(contract abstractions),并且進行了初始化,以方便你可以便利的與以太坊的網路互動,這些抽象介面都是部署流程的一部分,
更新 migration 檔案
將 2_deploy_contracts.js 的內容更新為以下資訊:
var Voting = artifacts.require("./Voting.sol");
module.exports = function(deployer) {
deployer.deploy(Voting, ['Alice', 'Bob', 'Cary'], {gas:
290000});
};
從上面可以看出,部署者希望第一個引數為合約名,跟在建構式引數后面,
在我們的例子中,只有一個引數,就是一個候選者陣列,第三個引數是一個哈希,我們用來指定部署代碼所需的 gas,gas 數量會隨著你的合約大小而變化,對于投票合約, 290000 就足夠了,
更新 truffle 組態檔
像下面這樣更新 truffle.js 的內容:
require('babel-register')
module.exports = {
networks: {
development: {
host: 'localhost',
port: 8545,
network_id: '*',
gas: 470000
} } }
你會注意到,之前的 truffle.js 與我們更新的檔案唯一區別在于 gas 選項,
這是一個會應用到所有 migration 的全域變數,比如,如果你沒有指定
2_deploy_contracts.js gas 值為 290000,migration 就會采用默認值 470000.
合約代碼Voting.sol
之前我們已經完成了編碼作業,無須額外改動即可用于 truffle,將檔案從
simple_voting_dapp 復制到 contracts 目錄即可,
創建賬戶(可用 metamask 上賬戶轉幣)
在能夠部署合約之前,我們需要一個里面有一些以太的賬戶,當我們用
ganache 的時候,它創建了 10 個測驗賬戶,每個賬戶里面有 100 個測驗以
太,但是對于測驗網和主網,我們必須自己創建賬戶,并往里面打一些以太,
在之前的 ganache 應用里,我們曾單獨啟動了一個 node 控制臺,并初始
化了 web3 物件,當我們執行 truffle 控制臺時,truffle 會幫我們做好所有準備,我們會有一個立即可用的 web3 物件,現在我們有一個賬戶,地址為
‘0x95a94979d86d9c32d1d2ab5ace2dcc8d1b446fa1’ (你會得到一個不同的地址),賬戶余額為 0,
>truffle console
// Replace 'verystrongpassword' with a good strong password.
truffle(development)>
web3.personal.newAccount('verystrongpassword') ' 0xbaeec91f6390a4eedad8729aea4bf47bf8769b15'
truffle(development)>
web3.eth.getBalance('0xbaeec91f6390a4eedad8729aea4bf47bf8769b1
5')
{ [String: '0'] s: 1, e: 0, c: [ 0 ] }
truffle(development)>
web3.personal.unlockAccount('0xbaeec91f6390a4eedad8729aea4bf47
bf8769b15', 'verystrongpassword', 15000)
部署
如果已經有了一些以太,我們就可以繼續編譯并把合約部署到區塊鏈上,你
可以在下面找到相關命令,如果一切順利,就會出現以下輸出,
>truffle compile
Compiling Migrations.sol...Compiling Voting.sol...Writing
artifacts to ./build/contracts
>truffle migrate
Running migration: 1_initial_migration.js
Deploying Migrations...
Migrations: 0x3cee101c94f8a06d549334372181bc5a7b3a8bee
Saving successful migration to network...
Saving artifacts...
Running migration: 2_deploy_contracts.js
Deploying Voting...
Voting: 0xd24a32f0ee12f5e9d233a2ebab5a53d4d4986203
Saving successful migration to network...
Saving artifacts...
如果你有多個賬戶,確保相關賬戶未被鎖定,默認情況,第一個賬戶
web3.eth.accounts[0] 會用于部署,
可能出現的問題和解決方案
- 如果由于 gas 不足而部署失敗,嘗試將
migrations/2_deploy_contracts.js 里面的 gas account 增加至
500000,比如:deployer.deploy(Voting, [‘Rama’, ‘Nick’, ‘Jose’],
{gas: 500000}); - 如果你有多個賬戶,并且更喜歡自選一個賬戶,而不是 accounts[0],你可以在 truffle.js 中指定想要使用的賬戶地址,在 network_id 后面添
加 ‘from: your address’,truffle 將會使用你指定的地址來部署和互動,
如果部署順利,你可以通過控制臺和網頁與合約進行互動
新建 JavaScript 檔案 app/scripts/index.js
// Import the page's CSS. Webpack will know what to do with it.
import "../styles/app.css";
// Import libraries we need.
import { default as Web3} from 'web3';
import { default as contract } from 'truffle-contract'
import voting_artifacts from '../../build/contracts/Voting.json'
var Voting = contract(voting_artifacts);
let candidates = {"Alice": "candidate-1", "Bob": "candidate-2",
"Cary": "candidate-3"}
window.voteForCandidate = function(candidate) {
let candidateName = $("#candidate").val();
try {
$("#msg").html("Vote has been submitted. The vote count
will increment as soon as the vote is recorded on the blockchain.
Please wait.")
$("#candidate").val("");
Voting.deployed().then(function(contractInstance) {
contractInstance.voteForCandidate(candidateName,
{gas: 140000,
from:web3.eth.accounts[0]})
.then(function() {
let div_id = candidates[candidateName];
return
contractInstance.totalVotesFor
.call(candidateName).then(function(v) {
$("#" + div_id).html(v.toString());
$("#msg").html("");
});
});
});
} catch (err) {
console.log(err);
}
}
$( document ).ready(function() {
if (typeof web3 !== 'undefined') {
console.warn("Using web3 detected from external
source like Metamask") // Use Mist/MetaMask's provider
window.web3 = new Web3(web3.currentProvider);
} else {
console.warn("No web3 detected. Falling back to
http://localhost:8545. You should remove this fallback when you
deploy live, as it's inherently insecure. Consider switching to
Metamask for development. More info here:
http://truffleframework.com/tutorials/truffle-and-metamask");
// fallback - use your fallback strategy (local node / hosted node
+ in-dapp id mgmt / fail)
window.web3 = new Web3(new
Web3.providers
.HttpProvider("http://localhost:8545"));
}
Voting.setProvider(web3.currentProvider);
let candidateNames = Object.keys(candidates);
for (var i = 0; i < candidateNames.length; i++) {
let name = candidateNames[i];
Voting.deployed().then(function(contractInstance) {
contractInstance.totalVotesFor
.call(name).then(function(v) {
$("#" + candidates[name])
.html(v.toString());
});
});
}
});
Line 7: 當你編譯部署好投票合約時,truffle 會將 abi 和部署好的地址存盤
到一個 build 目錄下面的 json 檔案,我們已經在之前討論了 abi ,我們會用
這個資訊來啟動一個 Voting 抽象,我們將會隨后用這個 abstraction 創建一個Voting 合約的實體,
Line 14: Voting.deployed() 回傳一個合約實體,truffle 的每一個呼叫會返
回一個 promise,這就是為什么我們在每一個交易呼叫時都使用 then().
控制臺互動需要重新打開一個新的 console
>truffle console
truffle(default)>
Voting.deployed().then(function(contractInstance)
{contractInstance.voteForCandidate('Alice').then(function(v)
{console.log(v)})})
{ blockHash:
'0x7229f668db0ac335cdd0c4c86e0394a35dd471a1095b8fafb52ebd76714
33156',
blockNumber: 469628,
contractAddress: null,
....
....
truffle(default)>
Voting.deployed().then(function(contractInstance)
{contractInstance.totalVotesFor.call('Alice').then(function(v)
{console.log(v)})})
{ [String: '1'] s: 1, e: 0, c: [ 1] }
在呼叫 voteForCandidate 方法之后需要稍等一下,因為發送交易需要時間;
注意,truffle 的所有呼叫都會回傳一個 promise,這就是為什么會看到每個
回應被包裝在 then() 函式下面;另外 totalVoteFor() 方法也可以不加.call() 直
接呼叫,不會發送交易,
發出的交易可以在 geth 的 log 輸出檔案中查到;如果我們連接的是測驗網
絡,可以在 etherscan 上 https://rinkeby.etherscan.io 查詢,
可以看到 truffle 默認的 gasPrice 是 100GWei,如果心疼,可以在 truffle.js 中更改,加上 gasPrice: 1000000000 將其改為 1GWei,重啟 truffle console 生效,
網頁互動
在控制臺用 webpack 啟動服務器:
>npm run dev
默認埠 8080,在瀏覽器訪問 localhost:8080 即可看到頁面,
如果安裝了 metamask,index.js 中會自動檢測并使用 metamask 作為 web3
Provider;所以應該注意把 metamask 切換到我們當前連接的網路,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/303362.html
標籤:區塊鏈
下一篇:專案管理(PMP)認證介紹
