Truffle詳解區塊鏈
本文介紹一個簡單的部署智能合約的方法:Truffle。
1、什么是Truffle ?
Truffle是針對基于以太坊的Solidity語言的一套開發框架。本身基于Javascript。Truffle為以太坊提供了開發環境、測試框架和資產管道(pipeline),旨在使以太坊開發更容易,使用Truffle你會得到:
內置智能合約編譯、鏈接、部署和二進制字節碼管理。
針對快速迭代開發的自動化合約測試。
可腳本化,可擴展的部署和遷移框架。
網絡管理,用于部署到任意數量的公共和私有網絡。
使用EthPM和NPM進行包安裝管理。
用于直接合約通信的交互式控制臺。
支持持續集成的可配置構建管道。
外部腳本運行程序可以在Truffle環境中執行腳本。
提供了合約抽象接口,可以直接通過var instance = Storage.deployed();拿到合約對象后,在Javascript中直接操作對應的合約函數。原理是使用了基于web3.js封裝的Ether Pudding工具包。簡化開發流程。
提供了控制臺,使用框架構建后,可以直接在命令行調用輸出結果,可極大方便開發調試。當開發基于Truffle的應用時,我們推薦使用 EthereumJS TestRPC。它是一個完整的運行在內存中的區塊鏈,僅僅存在于你開發設備上。它在執行交易時是實時返回的,而不等待默認的出塊時間,這樣你可以快速驗證你新寫的代碼,當出現錯誤時,也能即時反饋給你。它同時還是一個支持自動化測試的功能強大的客戶端。Truffle充分利用它的特性,能將測試運行時間提速近90%。最好使用TestRPC客戶端充分測試后,再使用這些客戶端。這些是完整的客戶端實現,包括挖礦,網絡,區塊及交易的處理,Truffle可以在不需要額外配置的情況下發布到這些客戶端。
下面我們從一個簡單的例子開始了解一下Truffle。
2、安裝Truffle
安裝完成后執行下面的命令,確保Truffle被正確的安裝:
3. 創建并初始化項目
初始化完成后的目錄結構如下:
contracts/ – 存放我們編寫的合約。
migrations/ – 存放遷移部署腳本。
test/ – 存放合約測試腳本
truffle.js – Truffle的配置文件
truffle init會給我們創建一個名叫MetaCoin的代幣應用。我們將這個默認的應用刪除,我們將編寫自己的合約。
4. 創建合約
接下來我們創建一個我們自己的合約,進入contracts目錄,創建Storage.sol合約文件。
Storage.sol合約的內容如下:
5. 編譯合約
接下來使用truffle compile命令編譯剛剛完成的Storage.sol合約
從控制臺的輸出中,我們可以看到合約編譯后的文件(artifacts)會寫入./build/contracts目錄中,這些合約編譯后的文件對于Truffle框架能否正常工作至關重要。請不要手動修改這些文件,因為即使修改了,再次執行編譯命令時又會被覆蓋掉。
Truffle默認只編譯自上次編譯后被修改過的合約,目的是為了減少不必要的編譯。如果你想編譯全部合約 ,可以使用–all選項。
合約編譯完成后,我們需要部署Storage.sol合約,在truffle中部署合約需要用到遷移腳本。下面我們進入migrations目錄中為Storage合約創建一個遷移腳本。
6. 遷移合約
遷移腳本是由一些Javascript文件組成,用來幫助你把合約發布到以太坊網絡中。之所以需要遷移腳本是因為你的部署需求會隨著時間改變。隨著你的項目的發展,你可以創建新的遷移腳本把這些變化的合約部署到區塊鏈上。之前你運行的遷移歷史記錄,會被一個特殊的Migrations.sol合約記錄在區塊鏈上,后面將對Migrations.sol合約進行詳細介紹。
移腳本的命名規則:文件名以數字開頭,一個描述性的后綴結尾。數字前綴是必須的,用于記錄移植是否成功。后綴僅是為了提高可讀性,以方便理解。
文件:2_storage_migration.js
6.1 artifacts.require()
在遷移腳本開頭,我們通過artifacts.require()方法告訴truffle我們將要與那個合約交互。這個方法類似于NodeJs中的require,但在這里,它返回的是一個合約抽象,我們可以在我們的遷移腳本的其余部分中使用這個合約抽象。artifacts.require()中使用的名字不是必須與合約源文件的文件名相同,相反,它應該與在合約源代碼中定義的合約類的名稱相同。
6.2 module .exports
在遷移腳本最后,我們通過module.exports到處一個函數,被遷移腳本導出的函數都應該接受一個 deployer 對象作為其第一個參數。deployer對象中的輔助函數在部署過程中提供了一種清晰的語法,用于部署智能合約,以及執行一些常見的任務,比如把發布后的對象保存下來供以后使用。這個 deployer 對象是部署任務的主接口,它的API在本文后面有講解。
好了,我們的一切準備工作都做好了,接下來我們就可以把Storage.sol部署到我們的區塊鏈上了,在上一章中我們把智能合約部署到geth私有鏈中,這次我們將把智能合約部署到Testrpc環境中。
如果你還沒有安裝Testrpc 那么先執行下面的安裝命令:
啟動testrpc
testrpc啟動成功后,回到myproject項目的目錄中,執行遷移命令
truffle migrate命令會執行所有的位于migrations目錄內所有的遷移腳本。如果你之前已成功執行過遷移腳本,那么truffle migrate僅會執行新創建的遷移。如果沒有新的遷移腳本,這個命令不會執行任何操作。可以使用選項–reset來重新執行全部遷移腳本。
6.3 初始化遷移合約
在本節開頭我們提到過一個特殊的Migrations.sol合約,那么現在就來詳細了解下這個特殊合約。為了使用遷移功能,Truffle要求你要有一個遷移合約。這個合約必須包含一個特定的接口,對于大多數項目來說,這個合約只會在第一次做遷移的時候被部署,以后都不會做任何的更改了。當你使用 truffle init 來創建一個項目的時候,它會默認創建這個合約。
文件名:contracts/Migration.sol
為了利用遷移的特性,你必須首先要部署Migration.sol合約。為此,創建以下遷移腳本:
文件名:migrations/1_initial_migrations.js
要部署其他合約,你可以遞增數字編號前綴來創建新的遷移腳本。
6.4 部署器(deployer)
你的遷移腳本會使用這deployer對象來組織部署任務。deployer對象會同步執行部署任務,因此你可以按順序編寫部署任務。
另外,deployer上的每一個函數都會返回一個promise,通過promise可以把有執行順序依賴關系的部署任務組成隊列。
6.5 deployer API
deployer對象包含許多方法,可以用來簡化你的遷移工作。
(1) deployer.deploy(CONTRACT, ARGS…, OPTIONS)
這個API是用來部署合約的,contract參數傳入需要部署的合約名字,args參數傳入合約的構造函數需要的參數,options是一個可選參數它的值是{overwrite: true/false}, 如果 overwrite 被設置成 false, 那么當這個合約之前已經部署過了,這個deployer就不會再部署這個合約,這在當一個合約的依賴是由一個外部合約地址提供的情況下是有用的。
為了快速進行部署多個合約,你可以向deployer.deploy(…..)函數中傳入一個或多個數組。
例子:
(2) deployer.link(LIBRARY, DESTINATIONS)
把一個已部署好的庫鏈接到一個或多個合約里. destinations 可以傳入一個合約,也可以傳入一組合約. 如果 destinations 中的某個合約不依賴這個庫, 那deployer 的link函數就會忽略這個合約。
(3) deployer.then(function() {…})
在遷移過程中使用它調用特定合約的函數來部署新的合約,為已部署的合約做一些初始化工作等。
例子:
(4) 網絡相關
在執行遷移時,遷移腳本會把truffle.js里配置的networks傳遞給你,你可以在module.exports導出函數中第二個參數位置接受這個值。
文件:truffle.js
例子:
(5) 可用的賬戶
在執行遷移時,遷移腳本會把當前以太坊客戶端或web3.provider中可用的賬戶列表傳遞給你,這個列表與web3.eth.getAccounts()返回的賬戶列表完全一樣。你可以在module.exports導出函數中第三個參數位置接受這個值。
7. 合約交互
以太坊中將向以太坊網絡寫入數據和從以太坊網絡中讀取數據這兩種操作做了區分。一般來說,寫數據被稱為交易(transaction),而讀取數據稱為調用(call)。交易和調用的處理方式非常不同,并且具有以下特征。
7.1 交易(transaction)
交易會從根本上改變了網絡的狀態。簡單的交易有:發送以太幣到另一個賬戶。復雜的交易有:調用一個合約的函數,向網絡中部署一個合約。交易的顯著特征是:
交易可以寫入或修改數據;
交易花費以太幣運行,就是我們所說的gas;
交易需要時間處理。
當你通過交易調用合約的函數時,我們將無法立即獲得智能合約的返回值,因為該交易當前只是被發送,離被打包、執行還有一段時間。通常,通過交易執行的函數將不會立刻返回值,它們將返回一個交易ID。所以總結一下,一個交易一般有如下特征:
消耗gas(以太幣)
更改網絡的狀態
不會立即處理
不會立刻返回一個返回值(只有一個交易ID)。
7.2 調用(CALL)
另一方面,調用則完全不一樣。調用可以在網絡上執行代碼,但不會永久更改數據。調用可以免費運行,不需要花費gas。調用的顯著特征是:調用是用來讀取數據。當你通過調用執行合約函數時,你將立即收到返回值。總而言之,調用是:
是免費的(不消耗gas)
不會更改網絡的狀態
會被立即處理
會立刻返回一個值
決定使用交易還是調用,依據很簡單:要讀取數據還是寫入數據。
7.3 合約抽象
合約抽象是Javascript和以太坊合約交互的中間層粘合劑。簡而言之,合約抽象幫我們封裝好了代碼,它可以讓你和合約之間的交互變得簡單,從而讓你不必關心合約調用細節。Truffle通過truffle-contract模塊來使用自己的合約抽象。合約抽象中的函數和我們合約中的函數是一樣的。
為了使用合約抽象和合約交互,我們需要通過npm安裝truffle-contract模塊
7.4 與合約交互
7.4.1. Call 方式交互
介紹完上述概念后,現在我們可以和之前部署好的Storage.sol合約交互了,首先我們以call方式調用合約。
文件:call.js
注意:
我們必須明確地調用.call()函數,告訴Ethereum網絡知道我們不會修改區塊鏈上的數據。
當調用成功是,我們會收到一個返回值,而不是交易ID。
7.4.2 ransaction 方式交互
接下來我們以transaction方式給Storage.sol合約中storedData變量賦值為42
文件:transaction.js
上面的代碼有一些需要說明的地方:
我們直接調用這合約抽象的 set 方法。 默認情況下,這個操作會向區塊鏈網絡中發送一筆交易。也可以顯式調用storageInstance.set.sendTransaction(42,{from:Storage.web3.eth.accounts[0]}),表明是以transaction方式交互
當這個交易成功發出后,回調函數只有在交易被成功打包處理后才會激活,這省去了你自己寫判斷語句檢查交易狀態的麻煩。
我們傳遞了一個對象給set函數的第二個參數。注意:在我們的Storage.sol合約代碼中set函數并沒有第三個參數,這第三個參數是合約抽象API里的。在合約抽象的所有函數中,你都可以向它們傳入一個對象作為最后一個參數,在這個對象中你可以寫入一些有關交易細節,在這個例子中,我們在對象中寫入from字段,以確保這個交易是來自 web3.eth.accounts[0]。
7.5 添加一個新合約到網絡
在上面的所有例子中,我們使用的是一個已部署好的合約抽象,我們可以使用合約抽象的.new()函數來部署自己的合約。
文件:new.js
1.TMT觀察網遵循行業規范,任何轉載的稿件都會明確標注作者和來源;
2.TMT觀察網的原創文章,請轉載時務必注明文章作者和"來源:TMT觀察網",不尊重原創的行為TMT觀察網或將追究責任;
3.作者投稿可能會經TMT觀察網編輯修改或補充。