Solidity智能合約開發(fā)技術(shù)與實(shí)戰(zhàn)-以太坊DApp開發(fā)框架Truffle_第1頁(yè)
Solidity智能合約開發(fā)技術(shù)與實(shí)戰(zhàn)-以太坊DApp開發(fā)框架Truffle_第2頁(yè)
Solidity智能合約開發(fā)技術(shù)與實(shí)戰(zhàn)-以太坊DApp開發(fā)框架Truffle_第3頁(yè)
Solidity智能合約開發(fā)技術(shù)與實(shí)戰(zhàn)-以太坊DApp開發(fā)框架Truffle_第4頁(yè)
Solidity智能合約開發(fā)技術(shù)與實(shí)戰(zhàn)-以太坊DApp開發(fā)框架Truffle_第5頁(yè)
已閱讀5頁(yè),還剩247頁(yè)未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

以太坊Solidity智能合約開發(fā)教程以太坊DApp開發(fā)框架Truffle學(xué)前提示Truffle是目前最流行的基于以太坊虛擬機(jī)的開發(fā)環(huán)境和測(cè)試框架。知識(shí)要點(diǎn)8.1Truffle開發(fā)框架概述8.2Truffle項(xiàng)目管理8.3智能合約編程8.4測(cè)試合約8.5Truffle示例項(xiàng)目寵物商店pet-shop8.1Truffle開發(fā)框架概述8.1.1Truffle開發(fā)框架的基本特性8.1.2安裝Truffle開發(fā)框架8.1.3選擇以太坊客戶端8.1.4個(gè)人區(qū)塊鏈Ganache8.1.1Truffle開發(fā)框架的基本特性·內(nèi)置智能合約編譯、鏈接、部署和二進(jìn)制管理等功能。相關(guān)內(nèi)容將在8.2節(jié)介紹;·自動(dòng)智能合約測(cè)試,從而實(shí)現(xiàn)快速開發(fā)。相關(guān)內(nèi)容將在8.4節(jié)介紹;·實(shí)現(xiàn)腳本化、可擴(kuò)展的部署和遷移。相關(guān)內(nèi)容將在8.2.4節(jié)介紹;·通過(guò)網(wǎng)絡(luò)管理實(shí)現(xiàn)將智能合約部署到任意數(shù)量的公有和私有網(wǎng)絡(luò);·利用EthPM和NPM實(shí)現(xiàn)程序包管理。由于篇幅所限,此部分內(nèi)容在本章中不做具體介紹;·提供直接與智能合約通信的交互控制臺(tái),便于開發(fā)調(diào)試。相關(guān)內(nèi)容將在8.3.2節(jié)介紹;·提供可配置的構(gòu)建、發(fā)布一體化解決方案。實(shí)現(xiàn)自動(dòng)構(gòu)建、自動(dòng)部署,無(wú)需每次修改都重新執(zhí)行整個(gè)流程;·提供外部腳本運(yùn)行器,可以在Truffle環(huán)境中執(zhí)行腳本。由于篇幅所限,此部分內(nèi)容在本章中不做具體介紹。8.1.2安裝Truffle開發(fā)框架npmconfigsetstrict-sslfalsenpminstall-gtruffle查看Truffle的版本truffleversionTrufflev5.1.65(core:5.1.65)Solidityv0.5.16(solc-js)Nodev10.13.0Web3.jsv1.2.9

8.1.3選擇以太坊客戶端1.開發(fā)時(shí)可以選擇使用的以太坊客戶端2.正式發(fā)布時(shí)可以選擇使用的以太坊客戶端1.開發(fā)時(shí)可以選擇使用的以太坊客戶端(1)EthereumJSTestRPC:一個(gè)完整的運(yùn)行于內(nèi)存中的以太坊客戶端,每個(gè)開發(fā)人員可以運(yùn)行自己的以太坊區(qū)塊鏈。EthereumJSTestRPC可以在執(zhí)行交易時(shí)實(shí)時(shí)返回,無(wú)需等待默認(rèn)的出塊時(shí)間,從而大大提高調(diào)試程序的效率。(2)Ganache:可以在桌面環(huán)境下運(yùn)行的,用于以太坊開發(fā)的個(gè)人區(qū)塊鏈,是Truffle套件的組成部分。使用Ganache可以簡(jiǎn)化開發(fā)DApp的過(guò)程。用戶可以很便捷地查看應(yīng)用程序?qū)^(qū)塊鏈的影響,包括賬戶信息、賬戶余額、智能合約的創(chuàng)建、以及花費(fèi)的Gas等??梢栽赪indows、Mac或Linux下安裝Ganache。2.正式發(fā)布時(shí)可以選擇使用的以太坊客戶端(1)Geth,GO語(yǔ)言版本的以太坊客戶端,本書2.4節(jié)對(duì)Geth客戶端進(jìn)行了詳細(xì)地介紹。其他章節(jié)也有多處使用Geth搭建的以太坊私有鏈作為演示案例。(2)HyperledgerBesu,企業(yè)級(jí)的、基于Java的以太坊客戶端,兼容以太坊主網(wǎng)??梢钥焖賳螕羝髽I(yè)的以太坊網(wǎng)絡(luò),并通過(guò)

JSONRPC與智能合約進(jìn)行交互。(3)Parity,快速、輕量級(jí)的以太坊客戶端。(4)Nethermind,.NETCore開發(fā)的以太坊客戶端,支持Linux、Windows和MacOS。8.1.4個(gè)人區(qū)塊鏈GanacheGanache是Truffle家族中的一款適用于快捷以太坊DApp開發(fā)的工具。它可以讓每個(gè)開發(fā)都擁有一個(gè)輕量級(jí)的、獨(dú)享的以太坊區(qū)塊鏈。1.下載和安裝Ganache可以從Truffle官網(wǎng)中的Ganache主頁(yè)下載Ganache,URL如下:/ganache2.創(chuàng)建工作空間Ganache的主界面創(chuàng)建Ganache工作空間單擊NEWWORKSPACE按鈕Ganache區(qū)塊鏈的詳情窗口在詳情窗口的頂部可以看到區(qū)塊號(hào)(CURRENTBLOCK)Gas價(jià)格(GASPRICE)Gas上限(GASLIMIT)硬分叉版本(HARDFORK)網(wǎng)絡(luò)ID(NETWORKID)挖礦狀態(tài)(MININGSTATUS)工作空間名稱圖形界面的Ganache和命令行工具ganache-cli圖形界面的Ganache區(qū)塊鏈默認(rèn)使用7545端口,而運(yùn)行命令行工具ganache-cli時(shí)啟動(dòng)的區(qū)塊鏈?zhǔn)褂?545端口。8.2Truffle項(xiàng)目管理8.2.1創(chuàng)建項(xiàng)目8.2.2配置Truffle項(xiàng)目8.2.3編譯合約8.2.4部署合約

8.2.1創(chuàng)建項(xiàng)目Truffle項(xiàng)目是基于智能合約的應(yīng)用中所有程序和資源的集合。1.TruffleBoxes2.使用Webpackbox創(chuàng)建Truffle項(xiàng)目3.webpack項(xiàng)目模板的目錄結(jié)構(gòu)4.創(chuàng)建空白Truffle項(xiàng)目1.TruffleBoxes項(xiàng)目模板熱度具體說(shuō)明react379由Truffle、Webpack和React構(gòu)成的模板drizzle161包含Drizzle開發(fā)包的React應(yīng)用,可以提供開發(fā)智能合約應(yīng)用所需的各種功能。Drizzle開發(fā)包由drizzle(基礎(chǔ)庫(kù))、drizzle-react(實(shí)現(xiàn)與React的兼容)和drizzle-react-components(一組React組件)組成DOkwufulueze/eth-vue111適合使用vue框架進(jìn)行dapp開發(fā)的用戶adrianmcli/truffle-next110使用Next.js快速開發(fā)以太坊DApp的示例項(xiàng)目模板。使用Next.js可以開發(fā)規(guī)?;?、生產(chǎn)級(jí)React應(yīng)用,可以實(shí)現(xiàn)零配置的自動(dòng)編譯和打包pet-shop108官方的寵物商店教程示例項(xiàng)目模板,8.5節(jié)中將以此項(xiàng)目模板為例介紹使用Truffle開發(fā)DApp的過(guò)程endless-nameless-inc/cheshire69CryptoKittiesDApp的開發(fā)者使用的沙箱。CryptoKitties是曾經(jīng)火爆一時(shí)的加密寵物貓以太坊應(yīng)用,一度造成以太坊網(wǎng)絡(luò)的擁堵。沙箱(SandBox)是一種技術(shù),在沙箱中,軟件運(yùn)行在操作系統(tǒng)受限制的環(huán)境中wespr/truffle-vue62作為所有Truffle+Vue實(shí)現(xiàn)DApp的底層基礎(chǔ),提供對(duì)Vue.js、vue-router、vuex、JavaScript和Solidity的支持Quintor/angular-truffle-box49使用Angular快速構(gòu)建DApp的項(xiàng)目模板tutorialtoken45提供使用OpenZeppelin框架開發(fā)代幣教程的示例項(xiàng)目模板。OpenZeppelinContracts是一個(gè)用于開發(fā)安全智能合約的庫(kù)metacoin44代幣智能合約示例項(xiàng)目模板webpack34基于Webpack的應(yīng)用程序的項(xiàng)目模板2.使用Webpackbox創(chuàng)建Truffle項(xiàng)目

創(chuàng)建目錄cd/usr/local/mkdirtrufflecdtrufflemkdirMetaCoin下載(拆箱)Webpack項(xiàng)目模板MetaCoincd/usr/local/truffle/MetaCointruffleunboxmetacoin涉及的GitHub相關(guān)域名包括查看對(duì)應(yīng)的IP地址在/etc/hosts中添加如下代碼,配置GitHub相關(guān)域名對(duì)應(yīng)的IP地址#GitHubStart

333333333333333333333333333333#GitHubEnd33333333333333333333#GitHubEnd

3.webpack項(xiàng)目模板的目錄結(jié)構(gòu)(1)app:保存一個(gè)通過(guò)Truffle框架與合約進(jìn)行交互的前端應(yīng)用實(shí)例。具體方法將在8.3節(jié)中介紹。(2)contracts:保存Solidity智能合約。webpack項(xiàng)目模板中包含如下智能合約?!onvertLib.sol,定義一個(gè)根據(jù)匯率計(jì)算金額的函數(shù)庫(kù);·MetaCoin.sol,定義一個(gè)簡(jiǎn)易代幣合約。有轉(zhuǎn)賬功能?!igrations.sol,初始遷移合約,此合約包含特定接口。關(guān)于Truffle的合約遷移功能將在8.2.4節(jié)介紹。(3)migrations:保存用于部署合約的腳本文件。MetaCoin項(xiàng)目模板中包含如下部署合約的腳本文件:·1_initial_migration.js,部署初始遷移合約Migrations.sol的腳本。·2_deploy_contracts.js,部署函數(shù)庫(kù)ConvertLib和合約MetaCoin的腳本。(4)test:保存測(cè)試腳本。關(guān)于如何在Truffle框架中測(cè)試合約將在8.4節(jié)介紹。4.創(chuàng)建空白Truffle項(xiàng)目truffleinit過(guò)程如下Startinginit...================>Copyingprojectfilesto/usr/local/truffle/myprojInitsuccessful,sweet!

8.2.2配置Truffle項(xiàng)目一個(gè)簡(jiǎn)單的networks節(jié)點(diǎn)定義如下:module.exports={networks:{development:{host:"",port:8545,network_id:"*"}}};參數(shù)說(shuō)明如下·development:指定配置數(shù)據(jù)應(yīng)用于開發(fā)環(huán)境。·host:指定以太坊節(jié)點(diǎn)的IP地址或域名?!ort:指定以太坊節(jié)點(diǎn)的監(jiān)聽端口號(hào)?!etwork_id:指定以太坊節(jié)點(diǎn)的網(wǎng)絡(luò)id。設(shè)置為"*"表示可匹配任意網(wǎng)絡(luò)。

Truffle使用的默認(rèn)編譯器是solcmodule.exports={compilers:{solc:{version:"0.5.1",}}}8.2.3編譯合約trufflecompile–-all在myproj項(xiàng)目目錄下執(zhí)行trufflecompile命令的過(guò)程在MetaCoin項(xiàng)目目錄下執(zhí)行trufflecompile命令的過(guò)程8.2.4部署合約1.遷移合約的命令2.在測(cè)試區(qū)塊鏈中部署合約3.遷移腳本文件4.初始化遷移1.遷移合約的命令trufflemigrate2.在測(cè)試區(qū)塊鏈中部署合約在CentOS中執(zhí)行如下命令,可以全局安裝ganache-cli。npminstall-gganache-cliganache-cli命令的執(zhí)行過(guò)程Truffle項(xiàng)目的配置文件module.exports={networks:{development:{host:"",port:8545,network_id:"*"}}};打開另外一個(gè)終端在MetaCoin的項(xiàng)目目錄下執(zhí)行trufflemigrate命令部署合約。在Truffle框架中部署合約的過(guò)程(1)編譯項(xiàng)目中的所有合約;(2)執(zhí)行1_initial_migration.js腳本,部署合約Migrations;(3)執(zhí)行2_deploy_contracts.jss腳本,部署函數(shù)庫(kù)ConvertLib和合約MetaCoin。3.遷移腳本文件默認(rèn)的1_initial_migration.js代碼如下:constMigrations=artifacts.require("Migrations");module.exports=function(deployer){deployer.deploy(Migrations);};2_deploy_contracts.js的代碼constConvertLib=artifacts.require("ConvertLib");constMetaCoin=artifacts.require("MetaCoin");module.exports=function(deployer){deployer.deploy(ConvertLib);deployer.link(ConvertLib,MetaCoin);deployer.deploy(MetaCoin);};artifacts.require()方法需要使用artifacts.require()方法指定要部署的合約。artifacts.require()與Node.js的require()方法作用類似,但這里用于返回指定的合約交易對(duì)象,在后面的代碼中可以利用此對(duì)象部署合約。artifacts.require()方法的參數(shù)是要部署的合約名稱。遷移腳本中需要使用module.exports語(yǔ)法導(dǎo)出一個(gè)函數(shù)。導(dǎo)出函數(shù)有一個(gè)deployer參數(shù),用于組織部署合約的功能。使用deployerdeploy()方法用于部署合約,deployer.link()方法用于將已經(jīng)部署的函數(shù)庫(kù)鏈接到指定的合約,方法如下:deployer.link(library,destinations)4.初始化遷移每個(gè)Truffle項(xiàng)目都有一個(gè)Migrations合約,用于實(shí)現(xiàn)合約遷移的特性。Migrations合約在第一次執(zhí)行遷移命令時(shí)會(huì)被部署,以后不會(huì)被更新。在項(xiàng)目目錄下執(zhí)行truffleinit命令可以創(chuàng)建Migrations合約。默認(rèn)的Migrations合約代碼pragmasolidity>=0.4.22<0.9.0;contractMigrations{addresspublicowner=msg.sender;uintpubliclast_completed_migration;modifierrestricted(){require(msg.sender==owner,"Thisfunctionisrestrictedtothecontract'sowner");_;}functionsetCompleted(uintcompleted)publicrestricted{last_completed_migration=completed;}}初始化遷移腳本1_initial_migration.jsconstMigrations=artifacts.require("Migrations");module.exports=function(deployer){deployer.deploy(Migrations);};8.3智能合約編程8.3.1與合約進(jìn)行交互8.3.2TruffleDevelop8.3.3Truffle框架與智能合約MetaCoin交互的前端應(yīng)用案例8.3.4在Truffle框架中使用MetaMask8.3.5使用TruffleReact框架開發(fā)基于以太坊智能合約的DApp8.3.1與合約進(jìn)行交互1.合約抽象2.執(zhí)行合約函數(shù)3.部署合約4.向合約發(fā)送以太幣5.truffle-contractAPI1.合約抽象Truffle框架中包含合約抽象層實(shí)現(xiàn)在Javascript中與以太坊合約的交互。合約抽象對(duì)與合約的交互進(jìn)行了封裝,從而使開發(fā)者可以忽略交互的一些底層實(shí)現(xiàn)細(xì)節(jié)(例如合約的ABI和字節(jié)碼),使開發(fā)過(guò)程變得更容易、更人性化。合約MetaCoin//SPDX-License-Identifier:MITpragmasolidity>=0.4.25<0.7.0;import"./ConvertLib.sol";//Thisisjustasimpleexampleofacoin-likecontract.//Itisnotstandardscompatibleandcannotbeexpectedtotalktoother//coin/tokencontracts.Ifyouwanttocreateastandards-compliant//token,see:/ConsenSys/Tokens.Cheers!contractMetaCoin{mapping(address=>uint)balances;eventTransfer(addressindexed_from,addressindexed_to,uint256_value);constructor()public{balances[tx.origin]=10000;}functionsendCoin(addressreceiver,uintamount)publicreturns(boolsufficient){if(balances[msg.sender]<amount)returnfalse;balances[msg.sender]-=amount;balances[receiver]+=amount;emitTransfer(msg.sender,receiver,amount);returntrue;}functiongetBalanceInEth(addressaddr)publicviewreturns(uint){returnConvertLib.convert(getBalance(addr),2);}functiongetBalance(addressaddr)publicviewreturns(uint){returnbalances[addr];}}查看合約抽象詳情的前提將合約MetaCoin部署在Ganache個(gè)人測(cè)試鏈中。首先執(zhí)行g(shù)anache-cli命令,啟動(dòng)Ganache個(gè)人測(cè)試鏈。然后在Truffle項(xiàng)目目錄下執(zhí)行truffleconsole命令可以打開Truffle控制臺(tái)。在>后面可以通過(guò)JavaScript語(yǔ)句與合約交互。在控制臺(tái)中執(zhí)行如下語(yǔ)句可以查看合約抽象的內(nèi)容truffle(development)>letinstance=awaitMetaCoin.deployed()truffle(development)>instance返回結(jié)果大致如下TruffleContract{constructor:{[Function:TruffleContract]_constructorMethods:{……},_properties:{……},_property_values:{},_json:{contractName:'MetaCoin',abi:[Array],metadata:

'{"compiler":{"version":"0.5.16+commit.9c3226ce"},"language":"Solidity","output":{"abi":[{……}',bytecode:'……',deployedBytecode:'……',immutableReferences:undefined,generatedSources:undefined,deployedGeneratedSources:undefined,sourceMap:……}2.執(zhí)行合約函數(shù)使用合約的deployed()方法可以獲得已經(jīng)部署的合約實(shí)例,方法如下:letinstance=awaitMetaCoin.deployed()通過(guò)合約實(shí)例來(lái)執(zhí)行合約函數(shù)如果被執(zhí)行的合約函數(shù)需要向區(qū)塊鏈上寫入數(shù)據(jù)(發(fā)起交易),則在執(zhí)行該函數(shù)時(shí)需要指定支付Gas的賬戶,方法如下:let返回結(jié)果=await合約實(shí)例.合約方法(參數(shù)列表,{from:支付賬戶})

發(fā)起交易時(shí)的result中包含如下信息·result.tx:一個(gè)字符串,表示交易的哈希?!esult.logs:一個(gè)數(shù)組,表示交易的日志?!esult.receipt:一個(gè)對(duì)象,表示交易的收據(jù)信息。

在Truffle控制臺(tái)中執(zhí)行如下語(yǔ)句可以調(diào)用合約MetaCoin的sendCoin()函數(shù)letinstance=awaitMetaCoin.deployed()letaccounts=awaitweb3.eth.getAccounts()instance.sendCoin(accounts[1],10,{from:accounts[0]})

返回結(jié)果如下'0xd1aa0e6e4d18d478bdd99eb5cfd67e8f7d2d0b765931b5bb4e4787b19b68f817',receipt:{transactionHash:'0xd1aa0e6e4d18d478bdd99eb5cfd67e8f7d2d0b765931b5bb4e4787b19b68f817',transactionIndex:0,blockHash:'0x1039d3dc0889a04b90c992f521d64f5ce9d3d522a634fabb03c6039fc8791bb6',

blockNumber:6,from:'0x0007447cf7cfd4f068eb6e2d6e21f94632ff74f2',to:'0xf6cca9b0f9d852d6a856ce91487d2635502d836a',gasUsed:51508,cumulativeGasUsed:51508,contractAddress:null,logs:[[Object]],status:true,logsBloom:'0x00000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000008000000000000000000000000000000000000000002000000000000000000001000000000000000000000000000000010000000000000000000000000020000000000000000000800000000000080000000000000000000000000000000000000000800000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000',rawLogs:[[Object]]},

logs:[{logIndex:0,transactionIndex:0,transactionHash:'0xd1aa0e6e4d18d478bdd99eb5cfd67e8f7d2d0b765931b5bb4e4787b19b68f817',blockHash:'0x1039d3dc0889a04b90c992f521d64f5ce9d3d522a634fabb03c6039fc8791bb6',blockNumber:6,address:'0xF6cca9b0F9d852D6a856CE91487d2635502d836a',type:'mined',removed:false,id:'log_3d27b5ba',event:'Transfer',args:[Result]}]}

執(zhí)行如下語(yǔ)句,可以調(diào)用合約MetaCoin的getBlance()函數(shù)letinstance=awaitMetaCoin.deployed()letbalance=awaitinstance.getBalance(accounts[0])balance.toNumber()3.部署合約除了可以使用trufflemigrate命令部署合約外,還可以在JavaScript程序中通過(guò)如下方法部署指定合約,并得到合約抽象。let合約抽象==await合約名.new()

例如部署合約MetaCoin并查看合約地址的代碼如下letInstance=awaitMetaCoin.new()Instance.address假定返回的合約地址如下:'0xb43b5F844bAd1376b88a032672C7A0938A596d17'

在JavaScript程序中可以通過(guò)合約地址獲取合約抽象let合約抽象=await合約名.at(合約地址);

4.向合約發(fā)送以太幣(1)調(diào)用合約抽象的sendTransaction()函數(shù)(2)使用instance.send()函數(shù)(1)調(diào)用合約抽象的sendTransaction()函數(shù)instance.sendTransaction({...}).then(function(result){//處理交易結(jié)果});交易對(duì)象sendTransaction()函數(shù)的參數(shù)是一個(gè)表示交易對(duì)象的JSON字符串。交易對(duì)象通常包含如下參數(shù):·from,發(fā)送Ether和支付Gas的賬戶;·to,接收Ether的賬戶;·gas,花費(fèi)的Gas數(shù)量;·gasPrice,Gas的價(jià)格;·轉(zhuǎn)賬,支付的金額;·data,數(shù)據(jù);·nonce,隨機(jī)數(shù);在向合約轉(zhuǎn)賬時(shí),無(wú)需指定參數(shù)to,指定參數(shù)from即可constinstance=awaitMyContract.deployed();constresult=awaitinstance.sendTransaction({from:accounts[0],web3.utils.toWei(1,"ether")}););

(2)使用instance.send()函數(shù)

使用方法與sendTransaction()函數(shù)相似。5.truffle-contractAPItruffle-contractAPI是Truffle框架基于Node.js和Web3.js封裝的,用于更方便地與智能合約進(jìn)行交互。安裝truffle-contractAPInpminstalltruffle-contract導(dǎo)入truffle-contractAPIvarTruffleContract=require("truffle-Contract")得到合約抽象對(duì)象varMetaCoinRegistry=contract(require("../build/contracts/MetaCoin.json"));注冊(cè)到指定的以太坊網(wǎng)絡(luò),比如Ganache測(cè)試鏈varprovider=newWviders.HttpProvider(":7545");MetaCoinRegistry.setProvider(provider);MetaCoinRegistry.setNetwork(5777);//rpcport獲取合約實(shí)例的方法MetaCoinRegistry.deployed().then(function(instance){//……}調(diào)用合約MetaCoin的sendCoin()函數(shù)向賬戶account1轉(zhuǎn)賬10ETHERinstance.sendCoin(account1,10,{from:account2});8.3.2TruffleDevelop1.TruffleDevelop與TruffleConsole的區(qū)別2.使用TruffleDevelop的方法1.TruffleDevelop與TruffleConsole的區(qū)別·TruffleConsole可以連接到任意指定的以太坊節(jié)點(diǎn);·TruffleDevelop內(nèi)置一個(gè)用于開發(fā)的測(cè)試區(qū)塊鏈,默認(rèn)連接至此區(qū)塊鏈。在如下情形下應(yīng)該選擇TruffleConsole:·已經(jīng)安裝并使用了以太坊客戶端,例如Ganache或Geth。·想要將智能合約部署到測(cè)試網(wǎng)絡(luò)或以太坊主網(wǎng)。因?yàn)槭褂肨ruffleConsole可以很方便的連接到指定的測(cè)試網(wǎng)絡(luò)或以太坊主網(wǎng)。關(guān)于以太坊測(cè)試網(wǎng)絡(luò)的基本情況將在第9章中介紹?!ば枰褂锰囟ǖ木W(wǎng)絡(luò)的特定賬戶時(shí),則使用TruffleConsole手動(dòng)配置連接到該網(wǎng)絡(luò)。在如下情形下應(yīng)該選擇TruffleDevelop:·對(duì)項(xiàng)目進(jìn)行測(cè)試,并且不急于部署項(xiàng)目?!げ灰笫褂锰囟ǖ馁~戶,只要使用測(cè)試賬戶即可?!げ恍枰惭b和使用獨(dú)立的區(qū)塊鏈。2.使用TruffleDevelop的方法3.Truffle命令命令具體說(shuō)明build使用現(xiàn)有配置執(zhí)行項(xiàng)目構(gòu)建工作流compile編譯智能合約config顯示用戶級(jí)別的配置選項(xiàng)console運(yùn)行TruffleConsole命令行工具create創(chuàng)建新的合約、遷移或測(cè)試,命令格式如下:

trufflecreate<artifact_type><ArtifactName>

<artifact_type>指定要?jiǎng)?chuàng)建的對(duì)象的類型,可以是contract、migration或test;<ArtifactName>指定要?jiǎng)?chuàng)建的對(duì)象名。根據(jù)參數(shù),trufflecreate命令會(huì)創(chuàng)建如下的文件:

contracts/ArtifactName.sol;

migrations/####_artifact_name.js,####代表編號(hào)和遷移腳本的標(biāo)識(shí),例如1_initial_migration.js和2_deploy_contracts.js。

tests/artifact_name.js3.Truffle命令命令具體說(shuō)明debug已交互的方式調(diào)試區(qū)塊鏈中的交易deploymigrate命令的別名,即部署合約develop運(yùn)行Truffledevelop命令行工具exec在Truffle開發(fā)框架環(huán)境中執(zhí)行JavaScript模塊help列出所有命令或指定命令的信息。格式如下:

trufflehelp[<command>]

init初始化一個(gè)新的空項(xiàng)目migrate潤(rùn)興遷移腳本,部署合約networks顯示每個(gè)網(wǎng)絡(luò)上部署的合約地址2.項(xiàng)目配置文件package.json{"name":"app","version":"1.0.0","description":"","private":true,"scripts":{"build":"webpack","dev":"webpack-dev-server"},"devDependencies":{"copy-webpack-plugin":"^5.0.5","webpack":"^4.41.2","webpack-cli":"^3.3.10","webpack-dev-server":"^3.9.0"},"dependencies":{"web3":"^1.2.4"}}在開發(fā)環(huán)境下,項(xiàng)目依賴如下插件·copy-webpack-plugin:webpack拷貝插件,用于將單個(gè)文件或整個(gè)目錄復(fù)制到構(gòu)建目錄下。執(zhí)行如下命令可以安裝copy-webpack-plugin插件。npminstallcopy-webpack-plugin--save-dev·webpack:webpack插件。·webpack-cli:webpack的命令行工具?!ebpack-dev-server:webpack官方提供的一個(gè)小型Express服務(wù)器,可以為webpack打包生成的資源文件提供Web服務(wù)。3.Webpack配置文件webpack.config.jsconstpath=require("path");constCopyWebpackPlugin=require("copy-webpack-plugin");module.exports={mode:'development',entry:"./src/index.js",output:{filename:"index.js",path:path.resolve(__dirname,"dist"),},plugins:[newCopyWebpackPlugin([{from:"./src/index.html",to:"index.html"}]),],devServer:{contentBase:path.join(__dirname,"dist"),compress:true},};webpack.config.js的作用·指定Webpack打包文件的入口(entry)和出口(output)。本例中指定將./src/index.js打包到dist?!な褂肅opyWebpackPlugin插件將./src/index.html復(fù)制到出口文件夾dist中?!な褂胐evServer指定webpack的開發(fā)服務(wù)器。contentBase配置devServerHTTP服務(wù)器的文件根目錄為dist。compress指定是否啟用gzip壓縮。5.index.jsimportWeb3from"web3";importmetaCoinArtifactfrom"../../build/contracts/MetaCoin.json";constApp={web3:null,account:null,meta:null,start:asyncfunction(){const{web3}=this;try{//getcontractinstanceconstnetworkId=await.getId();constdeployedNetwork=metaCoinAworks[networkId];this.meta=newweb3.eth.Contract(metaCoinArtifact.abi,deployedNetwork.address,);//getaccountsconstaccounts=awaitweb3.eth.getAccounts();this.account=accounts[0];this.refreshBalance();}catch(error){console.error("Couldnotconnecttocontractorchain.");}},refreshBalance:asyncfunction(){const{getBalance}=this.meta.methods;constbalance=awaitgetBalance(this.account).call();constbalanceElement=document.getElementsByClassName("balance")[0];balanceElement.innerHTML=balance;},sendCoin:asyncfunction(){constamount=parseInt(document.getElementById("amount").value);constreceiver=document.getElementById("receiver").value;this.setStatus("Initiatingtransaction...(pleasewait)");const{sendCoin}=this.meta.methods;awaitsendCoin(receiver,amount).send({from:this.account});this.setStatus("Transactioncomplete!");this.refreshBalance();},setStatus:function(message){conststatus=document.getElementById("status");status.innerHTML=message;},};window.App=App;window.addEventListener("load",function(){if(window.ethereum){//useMetaMask'sproviderApp.web3=newWeb3(window.ethereum);window.ethereum.enable();//getpermissiontoaccessaccounts}else{console.warn("Noweb3detected.Fallingbackto:8545.Youshouldremovethisfallbackwhenyoudeploylive",);//fallback-useyourfallbackstrategy(localnode/hostednode+in-dappidmgmt/fail)App.web3=newWeb3(newWviders.HttpProvider(":8545"),);}App.start();程序定義了如下幾個(gè)接口(1)start(2)refreshBalance(3)sendCoin(4)setStatus(1)start

使用.getId()獲取當(dāng)前以太坊的網(wǎng)絡(luò)Id(networkId)。

根據(jù)networkId從MetaCoin.json中獲取合約MetaCoin的部署網(wǎng)絡(luò)對(duì)象deployedNetwork。

根據(jù)合約MetaCoin的ABI和部署地址deployedNetwork.address得到合約實(shí)例meta。

調(diào)用web3.eth.getAccounts()獲取當(dāng)前網(wǎng)絡(luò)中的所有賬戶accounts,然后設(shè)置account為其中第一個(gè)賬戶。

調(diào)用meta.methods.getBalance(this.account)方法獲取account的余額,并將其顯示在網(wǎng)頁(yè)元素balanceElement中。(2)refreshBalance獲取第一個(gè)賬戶account的余額。account的值在start接口設(shè)置。(3)sendCoin

獲取id為amount的元素的值,將其賦值到amount變量中,以備作為轉(zhuǎn)賬的金額。

獲取id為receiver的元素的值,將其賦值到receiver變量中,以備作為接受轉(zhuǎn)賬的賬戶。

調(diào)用setStatus()方法在網(wǎng)頁(yè)中顯示("Initiatingtransaction...(pleasewait)"。

調(diào)用合約Meta的sendCoin()函數(shù),從調(diào)用者賬戶中轉(zhuǎn)賬amount個(gè)ETH到receiver者賬戶。

調(diào)用setStatus()方法在網(wǎng)頁(yè)中顯示("Transactioncomplete!"。

調(diào)用refreshBalance()方法獲取account的余額,并將其顯示在網(wǎng)頁(yè)元素balanceElement中。(4)setStatus在id為status的元素中顯示指定的信息message。6.index.html<body><h1>MetaCoin—ExampleTruffleDapp</h1><p>Youhave<strongclass="balance">loading...</strong>META</p><h1>SendMetaCoin</h1><labelfor="amount">Amount:</label><inputtype="text"id="amount"placeholder="e.g.95"/><labelfor="receiver">Toaddress:</label><inputtype="text"id="receiver"placeholder="e.g.0x93e66d9baea28c17d9fc393b53e3fbdd76899dae"/><buttononclick="App.sendCoin()">SendMetaCoin</button><pid="status"></p><p><strong>Hint:</strong>openthebrowserdeveloperconsoletoviewanyerrorsandwarnings.</p><scriptsrc="index.js"></script></body>index.html中定義的關(guān)鍵HTML元素元素類型元素id具體說(shuō)明inputamount用于輸入轉(zhuǎn)賬金額strongbalance用于顯示賬戶account的余額inputreceiver用于輸入接受轉(zhuǎn)賬的賬戶button無(wú),顯示文本為SendMetaCoin單擊此按鈕會(huì)調(diào)用App.sendCoin(),從調(diào)用者賬戶向receiver賬戶轉(zhuǎn)賬amount個(gè)ETH7.運(yùn)行項(xiàng)目(1)打開另一個(gè)終端運(yùn)行Ganache測(cè)試鏈。(2)參照8.2.2設(shè)置Truffle項(xiàng)目配置文件truffle-config.js的內(nèi)容。(3)在MetaCoin項(xiàng)目目錄下執(zhí)行如下命令,編譯并部署合約。

trufflecompiletrufflemigrate運(yùn)行項(xiàng)目目模板webpack中前端應(yīng)用的過(guò)程瀏覽項(xiàng)目模板webpack中前端應(yīng)用的頁(yè)面8.3.4在Truffle框架中使用MetaMaskMetaMask是一款開源的以太坊錢包,可以用來(lái)很方便地管理自己的以太幣。MetaMask可以瀏覽器插件的形式安裝,無(wú)需安裝任何客戶端。1.在Chrome瀏覽器中安裝MetaMask錢包http://metamask.io/點(diǎn)擊Download按鈕,打開下載頁(yè)面Chrome網(wǎng)上應(yīng)用店的MetaMask頁(yè)面確認(rèn)添加MetaMaskMetaMask的歡迎頁(yè)選擇錢包頁(yè)面是否幫助MetaMask完善產(chǎn)品創(chuàng)建密碼頁(yè)面私密備份密語(yǔ)頁(yè)面確認(rèn)私密備份密語(yǔ)頁(yè)面完成安裝頁(yè)面在瀏覽器的右上角出現(xiàn)擴(kuò)展程序圖標(biāo)對(duì)MetaMask擴(kuò)展程序進(jìn)行授權(quán)MetaMask錢包的主界面在MetaMask錢包中選擇連接的網(wǎng)MetaMask錢包中展示的以太坊賬戶及地址MetaMask錢包中的賬戶管理菜單2.在項(xiàng)目模板webpack內(nèi)置的前端應(yīng)用中使用MetaMask錢包單擊Firefox瀏覽器右上方的圖標(biāo),彈出下拉菜單,并選擇“附加組件”,打開Firefox插件管理頁(yè)面。在搜索框中輸入MetaMask,然后按下回車鍵,可以搜索與MetaMask有關(guān)的插件。MetaMask插件詳情頁(yè)確認(rèn)添加MetaMask插件“歡迎使用MetaMask”頁(yè)面連接到Ganache測(cè)試區(qū)塊鏈導(dǎo)入賬戶頁(yè)面

Ganache測(cè)試區(qū)塊鏈的測(cè)試賬戶和私鑰本實(shí)例涉及下面3個(gè)賬戶·默認(rèn)賬戶,即Ganache網(wǎng)絡(luò)的第一個(gè)測(cè)試賬戶,用于支付轉(zhuǎn)賬金額?!eceiver賬戶,在頁(yè)面中Toaddress文本框中錄入的賬戶,用于接收轉(zhuǎn)賬金額?!etaMask賬戶,在MetaMask錢包中導(dǎo)入的賬戶,用于支付交易的Gas。導(dǎo)入Ganache測(cè)試賬戶管理連接到Ganache測(cè)試區(qū)塊鏈的賬戶在項(xiàng)目模板webpack中前端應(yīng)用的頁(yè)面顯示當(dāng)前賬戶的余額確認(rèn)支付交易8.3.5使用TruffleReact框架開發(fā)基于以太坊智能合約的DAppReact是FaceBook的內(nèi)部項(xiàng)目,是用于構(gòu)建用戶界面的JavaScript腳本。它的特點(diǎn)是高性能和代碼邏輯簡(jiǎn)單。開源后廣受歡迎。1.React前端開發(fā)框架簡(jiǎn)介(1)引用React.js腳本<scriptcrossoriginsrc="/react@17/umd/react.development.js"></script><scriptcrossoriginsrc="/react-dom@17/umd/react-dom.development.js"></script>在生產(chǎn)環(huán)境下,可以通過(guò)如下方式引用React.js腳本<scriptcrossoriginsrc="/react@17/umd/duction.min.js"></script><scriptcrossoriginsrc="/react-dom@17/umd/duction.min.js"></script>【例8-1】<!DOCTYPEhtml><html><head><metacharset="UTF-8"/><title>HelloReact!</title><scriptsrc="/react/16.4.0/umd/react.development.js"></script><scriptsrc="/react-dom/16.4.0/umd/react-dom.development.js"></script><scriptsrc="/babel-standalone/6.26.0/babel.min.js"></script></head>【例8-1】<!DOCTYPEhtml><html><head><metacharset="UTF-8"/><title>HelloReact!</title><scriptsrc="/react/16.4.0/umd/react.development.js"></script><scriptsrc="/react-dom/16.4.0/umd/react-dom.development.js"></script><scriptsrc="/babel-standalone/6.26.0/babel.min.js"></script></head><body><divid="example"></div><scripttype="text/babel">ReactDOM.render( <h1>Hello,React!</h1>, document.getElementById('example'));</script></body></html>瀏覽例8-1的頁(yè)面(2)渲染React元素ReactDOM.render(<React元素>,<ReactDOM>)【例8-2】<scripttype="text/babel">functionClock(props){return(<div><h1>Hello,world!</h1><h2>現(xiàn)在是{props.date.toLocaleTimeString()}.</h2></div>);}</script>定義一個(gè)JavaScript函數(shù)tick(),用于調(diào)用Clock()函數(shù)functiontick(){ReactDOM.render(<Clockdate={newDate()}/>,document.getElementById('example'));}然后在頁(yè)面中通過(guò)setInterval()方法每隔1s調(diào)用依次tick()方法setInterval(tick,1000);瀏覽例sampleT2-2.html的頁(yè)面(3)ReactJSXJSX是對(duì)JavaScript的一種擴(kuò)展。在React中JSX用來(lái)聲明React元素。例如前面介紹的定義React元素的方法:constelement=<h1>Hello,world!</h1>;可以使用大括號(hào)來(lái)引用JavaScript表達(dá)式constelement=<imgsrc={user.logo}/>;也可以在大括號(hào)中設(shè)置元素的樣式varmyStyle={fontSize:30,color:'#FF0000'};ReactDOM.render(<h1style={myStyle}>Hello,React</h1>,document.getElementById('example'));React的注釋的格式{/*這里是注釋……*/}(4)React組件React組件可以是一個(gè)JavaScript函數(shù),也可以是JavaScript類。例如,下面的代碼就定義了一個(gè)名為HelloComponent的組件。

functionHelloComponent(props){return<h1>Hello{}!</h1>;}下面的代碼引用組件HelloComponent定義一個(gè)React元素constelement=<HelloComponentname="React"/>;也可以使用ES6類來(lái)定義一個(gè)React元素class<類名>extendsReact.Component{render(){return(<React.Fragment>//HTML代碼

</React.Fragment>);//endofrender}//endofreturn}////endofclass下面的代碼定義一個(gè)組件TableclassTableextendsReact.Component{render(){return(<table><tr><Columns/></tr></table>);}組件Table之中引用了組件Columns,定義代碼如下classColumnsextendsReact.Component{render(){return(<div><td>Hello</td><td>React</td></div>);}}首先參照3.1.3節(jié)在VisualStudioCode中安裝和配置solidity插件。然后運(yùn)行VisualStudioCode,在菜單中依次選擇File/Folder,打開準(zhǔn)備好的項(xiàng)目目錄,在src子目錄下創(chuàng)建demo.sol組件Table返回的HTML代碼如下<table><tr><div><td>Hello</td><td>React</td></div></tr></table>可以將React組件存儲(chǔ)在一個(gè)單獨(dú)的js文件中。使用時(shí)可以通過(guò)import語(yǔ)句導(dǎo)入import組件名from組件js文件(5)React狀態(tài)可以將React組件視為一個(gè)狀態(tài)機(jī),在與用戶進(jìn)行交互的過(guò)程中設(shè)置不同的狀態(tài),然后渲染UI,從而使頁(yè)面與數(shù)據(jù)保持一致。換言之,在React中,如果希望渲染頁(yè)面,不要直接操作DOM,只需要更新組件的狀態(tài)即可?!纠?-3】<!DOCTYPEhtml><html><head><metacharset="UTF-8"/><title>HelloReact!</title><scriptsrc="/react/16.4.0/umd/react.development.js"></script><scriptsrc="/react-dom/16.4.0/umd/react-dom.development.js"></script><scriptsrc="/babel-standalone/6.26.0/babel.min.js"></script></head><body><divid="box"></div><scripttype="text/babel">classClockextendsReact.Component{constructor(props){super(props);this.state={date:newDate()};}render(){return(<div><h1>React狀態(tài)的演示</h1><h2>現(xiàn)在是{this.state.date.toLocaleTimeString()}.</h2></div>);}}ReactDOM.render(<Clock/>,document.getElementById('box'));</script></body></html>瀏覽例8-3的頁(yè)面2.下載項(xiàng)目模板react首先在/usr/local/truffle目錄下創(chuàng)建react子目錄,用于保存項(xiàng)目模板react。cd/usr/local/truffle/mkdirreact然后執(zhí)行下面的命令下載項(xiàng)目模板react。cd/usr/local/truffle/reacttruffleunboxreact3.項(xiàng)目模板react的前端應(yīng)用目錄結(jié)構(gòu)目錄或文件名類型上級(jí)目錄說(shuō)

明client目錄react保存項(xiàng)目的前端應(yīng)用代碼contracts目錄react保存項(xiàng)目的智能合約腳本migrations文件react保存項(xiàng)目中智能合約的遷移腳本test目錄react保存測(cè)試智能合約的腳本,包含一個(gè)JavaScript測(cè)試腳本和一個(gè)Solidity腳本truffle-config.js文件reactTruffle項(xiàng)目的配置文件node_modules目錄react/client被Node.js用于存放包管理工具下載和安裝的包package.json文件react/clientNode.js項(xiàng)目的配置文件package-lock.json文件react/client描述node_modules中所有模塊的版本信息、模塊來(lái)源及依賴的小版本信息public目錄react/client保存前端應(yīng)用的資源文件,包括HTML文件和圖片文件等src目錄react/client保存前端應(yīng)用的源代碼,包括.js文件和.css文件App.css文件react/client/srcReact組件App所使用的的樣式文件App.js文件react/client/src定義React組件App目錄或文件名類型上級(jí)目錄說(shuō)

明App.test.js文件react/client/src組件App的測(cè)試腳本getWeb3.js文件react/client/src用于初始化Web3.js的腳本index.js文件react/client/srcReact項(xiàng)目的入口腳本index.css文件react/client/srcindex.js對(duì)應(yīng)的樣式文件serviceWorker.js文件react/client/src一個(gè)獨(dú)立于當(dāng)前網(wǎng)頁(yè)在后臺(tái)運(yùn)行的腳本??梢杂糜趯?shí)現(xiàn)離線應(yīng)用,或大規(guī)模的后臺(tái)數(shù)據(jù)處理index.html文件react/client/public保存前端應(yīng)用的頁(yè)面模板manifest.json文件react/client/public前端應(yīng)用的配置文件,用于指定應(yīng)用的名稱和圖標(biāo)等SimpleStorage.json文件react/contracts部署合約SimpleStorage后得到的合約抽象文件項(xiàng)目模板react中前端資源文件的引用關(guān)系4.編譯和部署合約compilemigrate–reset編譯成功后會(huì)在client/src/contracts目錄下生成Migrations.json和SimpleStorage.json兩個(gè)文件。在前端應(yīng)用中會(huì)通過(guò)SimpleStorage.json與合約SimpleStorage進(jìn)行交互。5.index.jsimportReactfrom'react';importReactDOMfrom'react-dom';import'./index.css';importAppfrom'./App';import*asserviceWorkerfrom'./serviceWorker';ReactDOM.render(<App/>,document.getElementById('root'));//Ifyouwantyourapptoworkofflineandloadfaster,youcanchange//unregister()toregister()below.Notethiscomeswithsomepitfalls.//Learnmoreaboutserviceworkers:https://bit.ly/CRA-PWAserviceWorker.unregister();6.App.jsclassAppextendsComponent{state={storageValue:0,web3:

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論