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

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

以太坊Solidity智能合約開發(fā)教程以太坊DApp開發(fā)框架Truffle學前提示Truffle是目前最流行的基于以太坊虛擬機的開發(fā)環(huán)境和測試框架。知識要點8.1Truffle開發(fā)框架概述8.2Truffle項目管理8.3智能合約編程8.4測試合約8.5Truffle示例項目寵物商店pet-shop8.1Truffle開發(fā)框架概述8.1.1Truffle開發(fā)框架的基本特性8.1.2安裝Truffle開發(fā)框架8.1.3選擇以太坊客戶端8.1.4個人區(qū)塊鏈Ganache8.1.1Truffle開發(fā)框架的基本特性·內置智能合約編譯、鏈接、部署和二進制管理等功能。相關內容將在8.2節(jié)介紹;·自動智能合約測試,從而實現快速開發(fā)。相關內容將在8.4節(jié)介紹;·實現腳本化、可擴展的部署和遷移。相關內容將在8.2.4節(jié)介紹;·通過網絡管理實現將智能合約部署到任意數量的公有和私有網絡;·利用EthPM和NPM實現程序包管理。由于篇幅所限,此部分內容在本章中不做具體介紹;·提供直接與智能合約通信的交互控制臺,便于開發(fā)調試。相關內容將在8.3.2節(jié)介紹;·提供可配置的構建、發(fā)布一體化解決方案。實現自動構建、自動部署,無需每次修改都重新執(zhí)行整個流程;·提供外部腳本運行器,可以在Truffle環(huán)境中執(zhí)行腳本。由于篇幅所限,此部分內容在本章中不做具體介紹。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ā)時可以選擇使用的以太坊客戶端2.正式發(fā)布時可以選擇使用的以太坊客戶端1.開發(fā)時可以選擇使用的以太坊客戶端(1)EthereumJSTestRPC:一個完整的運行于內存中的以太坊客戶端,每個開發(fā)人員可以運行自己的以太坊區(qū)塊鏈。EthereumJSTestRPC可以在執(zhí)行交易時實時返回,無需等待默認的出塊時間,從而大大提高調試程序的效率。(2)Ganache:可以在桌面環(huán)境下運行的,用于以太坊開發(fā)的個人區(qū)塊鏈,是Truffle套件的組成部分。使用Ganache可以簡化開發(fā)DApp的過程。用戶可以很便捷地查看應用程序對區(qū)塊鏈的影響,包括賬戶信息、賬戶余額、智能合約的創(chuàng)建、以及花費的Gas等??梢栽赪indows、Mac或Linux下安裝Ganache。2.正式發(fā)布時可以選擇使用的以太坊客戶端(1)Geth,GO語言版本的以太坊客戶端,本書2.4節(jié)對Geth客戶端進行了詳細地介紹。其他章節(jié)也有多處使用Geth搭建的以太坊私有鏈作為演示案例。(2)HyperledgerBesu,企業(yè)級的、基于Java的以太坊客戶端,兼容以太坊主網??梢钥焖賳螕羝髽I(yè)的以太坊網絡,并通過

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

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

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

333333333333333333333333333333#GitHubEnd33333333333333333333#GitHubEnd

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

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

Truffle使用的默認編譯器是solcmodule.exports={compilers:{solc:{version:"0.5.1",}}}8.2.3編譯合約trufflecompile–-all在myproj項目目錄下執(zhí)行trufflecompile命令的過程在MetaCoin項目目錄下執(zhí)行trufflecompile命令的過程8.2.4部署合約1.遷移合約的命令2.在測試區(qū)塊鏈中部署合約3.遷移腳本文件4.初始化遷移1.遷移合約的命令trufflemigrate2.在測試區(qū)塊鏈中部署合約在CentOS中執(zhí)行如下命令,可以全局安裝ganache-cli。npminstall-gganache-cliganache-cli命令的執(zhí)行過程Truffle項目的配置文件module.exports={networks:{development:{host:"",port:8545,network_id:"*"}}};打開另外一個終端在MetaCoin的項目目錄下執(zhí)行trufflemigrate命令部署合約。在Truffle框架中部署合約的過程(1)編譯項目中的所有合約;(2)執(zhí)行1_initial_migration.js腳本,部署合約Migrations;(3)執(zhí)行2_deploy_contracts.jss腳本,部署函數庫ConvertLib和合約MetaCoin。3.遷移腳本文件默認的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()方法作用類似,但這里用于返回指定的合約交易對象,在后面的代碼中可以利用此對象部署合約。artifacts.require()方法的參數是要部署的合約名稱。遷移腳本中需要使用module.exports語法導出一個函數。導出函數有一個deployer參數,用于組織部署合約的功能。使用deployerdeploy()方法用于部署合約,deployer.link()方法用于將已經部署的函數庫鏈接到指定的合約,方法如下:deployer.link(library,destinations)4.初始化遷移每個Truffle項目都有一個Migrations合約,用于實現合約遷移的特性。Migrations合約在第一次執(zhí)行遷移命令時會被部署,以后不會被更新。在項目目錄下執(zhí)行truffleinit命令可以創(chuàng)建Migrations合約。默認的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與合約進行交互8.3.2TruffleDevelop8.3.3Truffle框架與智能合約MetaCoin交互的前端應用案例8.3.4在Truffle框架中使用MetaMask8.3.5使用TruffleReact框架開發(fā)基于以太坊智能合約的DApp8.3.1與合約進行交互1.合約抽象2.執(zhí)行合約函數3.部署合約4.向合約發(fā)送以太幣5.truffle-contractAPI1.合約抽象Truffle框架中包含合約抽象層實現在Javascript中與以太坊合約的交互。合約抽象對與合約的交互進行了封裝,從而使開發(fā)者可以忽略交互的一些底層實現細節(jié)(例如合約的ABI和字節(jié)碼),使開發(fā)過程變得更容易、更人性化。合約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個人測試鏈中。首先執(zhí)行ganache-cli命令,啟動Ganache個人測試鏈。然后在Truffle項目目錄下執(zhí)行truffleconsole命令可以打開Truffle控制臺。在>后面可以通過JavaScript語句與合約交互。在控制臺中執(zhí)行如下語句可以查看合約抽象的內容truffle(development)>letinstance=awaitMetaCoin.deployed()truffle(development)>instance返回結果大致如下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í)行合約函數使用合約的deployed()方法可以獲得已經部署的合約實例,方法如下:letinstance=awaitMetaCoin.deployed()通過合約實例來執(zhí)行合約函數如果被執(zhí)行的合約函數需要向區(qū)塊鏈上寫入數據(發(fā)起交易),則在執(zhí)行該函數時需要指定支付Gas的賬戶,方法如下:let返回結果=await合約實例.合約方法(參數列表,{from:支付賬戶})

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

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

返回結果如下'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í)行如下語句,可以調用合約MetaCoin的getBlance()函數letinstance=awaitMetaCoin.deployed()letbalance=awaitinstance.getBalance(accounts[0])balance.toNumber()3.部署合約除了可以使用trufflemigrate命令部署合約外,還可以在JavaScript程序中通過如下方法部署指定合約,并得到合約抽象。let合約抽象==await合約名.new()

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

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

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

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

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

trufflecreate<artifact_type><ArtifactName>

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

contracts/ArtifactName.sol;

migrations/####_artifact_name.js,####代表編號和遷移腳本的標識,例如1_initial_migration.js和2_deploy_contracts.js。

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

trufflehelp[<command>]

init初始化一個新的空項目migrate潤興遷移腳本,部署合約networks顯示每個網絡上部署的合約地址2.項目配置文件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)境下,項目依賴如下插件·copy-webpack-plugin:webpack拷貝插件,用于將單個文件或整個目錄復制到構建目錄下。執(zhí)行如下命令可以安裝copy-webpack-plugin插件。npminstallcopy-webpack-plugin--save-dev·webpack:webpack插件?!ebpack-cli:webpack的命令行工具?!ebpack-dev-server:webpack官方提供的一個小型Express服務器,可以為webpack打包生成的資源文件提供Web服務。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復制到出口文件夾dist中?!な褂胐evServer指定webpack的開發(fā)服務器。contentBase配置devServerHTTP服務器的文件根目錄為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();程序定義了如下幾個接口(1)start(2)refreshBalance(3)sendCoin(4)setStatus(1)start

使用.getId()獲取當前以太坊的網絡Id(networkId)。

根據networkId從MetaCoin.json中獲取合約MetaCoin的部署網絡對象deployedNetwork。

根據合約MetaCoin的ABI和部署地址deployedNetwork.address得到合約實例meta。

調用web3.eth.getAccounts()獲取當前網絡中的所有賬戶accounts,然后設置account為其中第一個賬戶。

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

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

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

調用setStatus()方法在網頁中顯示("Initiatingtransaction...(pleasewait)"。

調用合約Meta的sendCoin()函數,從調用者賬戶中轉賬amount個ETH到receiver者賬戶。

調用setStatus()方法在網頁中顯示("Transactioncomplete!"。

調用refreshBalance()方法獲取account的余額,并將其顯示在網頁元素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中定義的關鍵HTML元素元素類型元素id具體說明inputamount用于輸入轉賬金額strongbalance用于顯示賬戶account的余額inputreceiver用于輸入接受轉賬的賬戶button無,顯示文本為SendMetaCoin單擊此按鈕會調用App.sendCoin(),從調用者賬戶向receiver賬戶轉賬amount個ETH7.運行項目(1)打開另一個終端運行Ganache測試鏈。(2)參照8.2.2設置Truffle項目配置文件truffle-config.js的內容。(3)在MetaCoin項目目錄下執(zhí)行如下命令,編譯并部署合約。

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

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

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

</React.Fragment>);//endofrender}//endofreturn}////endofclass下面的代碼定義一個組件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插件。然后運行VisualStudioCode,在菜單中依次選擇File/Folder,打開準備好的項目目錄,在src子目錄下創(chuàng)建demo.sol組件Table返回的HTML代碼如下<table><tr><div><td>Hello</td><td>React</td></div></tr></table>可以將React組件存儲在一個單獨的js文件中。使用時可以通過import語句導入import組件名from組件js文件(5)React狀態(tài)可以將React組件視為一個狀態(tài)機,在與用戶進行交互的過程中設置不同的狀態(tài),然后渲染UI,從而使頁面與數據保持一致。換言之,在React中,如果希望渲染頁面,不要直接操作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>現在是{this.state.date.toLocaleTimeString()}.</h2></div>);}}ReactDOM.render(<Clock/>,document.getElementById('box'));</script></body></html>瀏覽例8-3的頁面2.下載項目模板react首先在/usr/local/truffle目錄下創(chuàng)建react子目錄,用于保存項目模板react。cd/usr/local/truffle/mkdirreact然后執(zhí)行下面的命令下載項目模板react。cd/usr/local/truffle/reacttruffleunboxreact3.項目模板react的前端應用目錄結構目錄或文件名類型上級目錄說

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

明App.test.js文件react/client/src組件App的測試腳本getWeb3.js文件react/client/src用于初始化Web3.js的腳本index.js文件react/client/srcReact項目的入口腳本index.css文件react/client/srcindex.js對應的樣式文件serviceWorker.js文件react/client/src一個獨立于當前網頁在后臺運行的腳本??梢杂糜趯崿F離線應用,或大規(guī)模的后臺數據處理index.html文件react/client/public保存前端應用的頁面模板manifest.json文件react/client/public前端應用的配置文件,用于指定應用的名稱和圖標等SimpleStorage.json文件react/contracts部署合約SimpleStorage后得到的合約抽象文件項目模板react中前端資源文件的引用關系4.編譯和部署合約compilemigrate–reset編譯成功后會在client/src/contracts目錄下生成Migrations.json和SimpleStorage.json兩個文件。在前端應用中會通過SimpleStorage.json與合約SimpleStorage進行交互。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. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論