Solidity智能合约开发技术与实战-以太坊DApp开发框架Truffle_第1页
Solidity智能合约开发技术与实战-以太坊DApp开发框架Truffle_第2页
Solidity智能合约开发技术与实战-以太坊DApp开发框架Truffle_第3页
Solidity智能合约开发技术与实战-以太坊DApp开发框架Truffle_第4页
Solidity智能合约开发技术与实战-以太坊DApp开发框架Truffle_第5页
已阅读5页,还剩247页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

以太坊Solidity智能合约开发教程以太坊DApp开发框架Truffle学前提示Truffle是目前最流行的基于以太坊虚拟机的开发环境和测试框架。知识要点8.1Truffle开发框架概述8.2Truffle项目管理8.3智能合约编程8.4测试合约8.5Truffle示例项目宠物商店pet-shop8.1Truffle开发框架概述8.1.1Truffle开发框架的基本特性8.1.2安装Truffle开发框架8.1.3选择以太坊客户端8.1.4个人区块链Ganache8.1.1Truffle开发框架的基本特性·内置智能合约编译、链接、部署和二进制管理等功能。相关内容将在8.2节介绍;·自动智能合约测试,从而实现快速开发。相关内容将在8.4节介绍;·实现脚本化、可扩展的部署和迁移。相关内容将在8.2.4节介绍;·通过网络管理实现将智能合约部署到任意数量的公有和私有网络;·利用EthPM和NPM实现程序包管理。由于篇幅所限,此部分内容在本章中不做具体介绍;·提供直接与智能合约通信的交互控制台,便于开发调试。相关内容将在8.3.2节介绍;·提供可配置的构建、发布一体化解决方案。实现自动构建、自动部署,无需每次修改都重新执行整个流程;·提供外部脚本运行器,可以在Truffle环境中执行脚本。由于篇幅所限,此部分内容在本章中不做具体介绍。8.1.2安装Truffle开发框架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.开发时可以选择使用的以太坊客户端2.正式发布时可以选择使用的以太坊客户端1.开发时可以选择使用的以太坊客户端(1)EthereumJSTestRPC:一个完整的运行于内存中的以太坊客户端,每个开发人员可以运行自己的以太坊区块链。EthereumJSTestRPC可以在执行交易时实时返回,无需等待默认的出块时间,从而大大提高调试程序的效率。(2)Ganache:可以在桌面环境下运行的,用于以太坊开发的个人区块链,是Truffle套件的组成部分。使用Ganache可以简化开发DApp的过程。用户可以很便捷地查看应用程序对区块链的影响,包括账户信息、账户余额、智能合约的创建、以及花费的Gas等。可以在Windows、Mac或Linux下安装Ganache。2.正式发布时可以选择使用的以太坊客户端(1)Geth,GO语言版本的以太坊客户端,本书2.4节对Geth客户端进行了详细地介绍。其他章节也有多处使用Geth搭建的以太坊私有链作为演示案例。(2)HyperledgerBesu,企业级的、基于Java的以太坊客户端,兼容以太坊主网。可以快速单击企业的以太坊网络,并通过

JSONRPC与智能合约进行交互。(3)Parity,快速、轻量级的以太坊客户端。(4)Nethermind,.NETCore开发的以太坊客户端,支持Linux、Windows和MacOS。8.1.4个人区块链GanacheGanache是Truffle家族中的一款适用于快捷以太坊DApp开发的工具。它可以让每个开发都拥有一个轻量级的、独享的以太坊区块链。1.下载和安装Ganache可以从Truffle官网中的Ganache主页下载Ganache,URL如下:/ganache2.创建工作空间Ganache的主界面创建Ganache工作空间单击NEWWORKSPACE按钮Ganache区块链的详情窗口在详情窗口的顶部可以看到区块号(CURRENTBLOCK)Gas价格(GASPRICE)Gas上限(GASLIMIT)硬分叉版本(HARDFORK)网络ID(NETWORKID)挖矿状态(MININGSTATUS)工作空间名称图形界面的Ganache和命令行工具ganache-cli图形界面的Ganache区块链默认使用7545端口,而运行命令行工具ganache-cli时启动的区块链使用8545端口。8.2Truffle项目管理8.2.1创建项目8.2.2配置Truffle项目8.2.3编译合约8.2.4部署合约

8.2.1创建项目Truffle项目是基于智能合约的应用中所有程序和资源的集合。1.TruffleBoxes2.使用Webpackbox创建Truffle项目3.webpack项目模板的目录结构4.创建空白Truffle项目1.TruffleBoxes项目模板热度具体说明react379由Truffle、Webpack和React构成的模板drizzle161包含Drizzle开发包的React应用,可以提供开发智能合约应用所需的各种功能。Drizzle开发包由drizzle(基础库)、drizzle-react(实现与React的兼容)和drizzle-react-components(一组React组件)组成DOkwufulueze/eth-vue111适合使用vue框架进行dapp开发的用户adrianmcli/truffle-next110使用Next.js快速开发以太坊DApp的示例项目模板。使用Next.js可以开发规模化的、生产级React应用,可以实现零配置的自动编译和打包pet-shop108官方的宠物商店教程示例项目模板,8.5节中将以此项目模板为例介绍使用Truffle开发DApp的过程endless-nameless-inc/cheshire69CryptoKittiesDApp的开发者使用的沙箱。CryptoKitties是曾经火爆一时的加密宠物猫以太坊应用,一度造成以太坊网络的拥堵。沙箱(SandBox)是一种技术,在沙箱中,软件运行在操作系统受限制的环境中wespr/truffle-vue62作为所有Truffle+Vue实现DApp的底层基础,提供对Vue.js、vue-router、vuex、JavaScript和Solidity的支持Quintor/angular-truffle-box49使用Angular快速构建DApp的项目模板tutorialtoken45提供使用OpenZeppelin框架开发代币教程的示例项目模板。OpenZeppelinContracts是一个用于开发安全智能合约的库metacoin44代币智能合约示例项目模板webpack34基于Webpack的应用程序的项目模板2.使用Webpackbox创建Truffle项目

创建目录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节中介绍。(2)contracts:保存Solidity智能合约。webpack项目模板中包含如下智能合约。·ConvertLib.sol,定义一个根据汇率计算金额的函数库;·MetaCoin.sol,定义一个简易代币合约。有转账功能。·Migrations.sol,初始迁移合约,此合约包含特定接口。关于Truffle的合约迁移功能将在8.2.4节介绍。(3)migrations:保存用于部署合约的脚本文件。MetaCoin项目模板中包含如下部署合约的脚本文件:·1_initial_migration.js,部署初始迁移合约Migrations.sol的脚本。·2_deploy_contracts.js,部署函数库ConvertLib和合约MetaCoin的脚本。(4)test:保存测试脚本。关于如何在Truffle框架中测试合约将在8.4节介绍。4.创建空白Truffle项目truffleinit过程如下Startinginit...================>Copyingprojectfilesto/usr/local/truffle/myprojInitsuccessful,sweet!

8.2.2配置Truffle项目一个简单的networks节点定义如下:module.exports={networks:{development:{host:"",port:8545,network_id:"*"}}};参数说明如下·development:指定配置数据应用于开发环境。·host:指定以太坊节点的IP地址或域名。·port:指定以太坊节点的监听端口号。·network_id:指定以太坊节点的网络id。设置为"*"表示可匹配任意网络。

Truffle使用的默认编译器是solcmodule.exports={compilers:{solc:{version:"0.5.1",}}}8.2.3编译合约trufflecompile–-all在myproj项目目录下执行trufflecompile命令的过程在MetaCoin项目目录下执行trufflecompile命令的过程8.2.4部署合约1.迁移合约的命令2.在测试区块链中部署合约3.迁移脚本文件4.初始化迁移1.迁移合约的命令trufflemigrate2.在测试区块链中部署合约在CentOS中执行如下命令,可以全局安装ganache-cli。npminstall-gganache-cliganache-cli命令的执行过程Truffle项目的配置文件module.exports={networks:{development:{host:"",port:8545,network_id:"*"}}};打开另外一个终端在MetaCoin的项目目录下执行trufflemigrate命令部署合约。在Truffle框架中部署合约的过程(1)编译项目中的所有合约;(2)执行1_initial_migration.js脚本,部署合约Migrations;(3)执行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合约在第一次执行迁移命令时会被部署,以后不会被更新。在项目目录下执行truffleinit命令可以创建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框架开发基于以太坊智能合约的DApp8.3.1与合约进行交互1.合约抽象2.执行合约函数3.部署合约4.向合约发送以太币5.truffle-contractAPI1.合约抽象Truffle框架中包含合约抽象层实现在Javascript中与以太坊合约的交互。合约抽象对与合约的交互进行了封装,从而使开发者可以忽略交互的一些底层实现细节(例如合约的ABI和字节码),使开发过程变得更容易、更人性化。合约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个人测试链中。首先执行ganache-cli命令,启动Ganache个人测试链。然后在Truffle项目目录下执行truffleconsole命令可以打开Truffle控制台。在>后面可以通过JavaScript语句与合约交互。在控制台中执行如下语句可以查看合约抽象的内容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.执行合约函数使用合约的deployed()方法可以获得已经部署的合约实例,方法如下:letinstance=awaitMetaCoin.deployed()通过合约实例来执行合约函数如果被执行的合约函数需要向区块链上写入数据(发起交易),则在执行该函数时需要指定支付Gas的账户,方法如下:let返回结果=await合约实例.合约方法(参数列表,{from:支付账户})

发起交易时的result中包含如下信息·result.tx:一个字符串,表示交易的哈希。·result.logs:一个数组,表示交易的日志。·result.receipt:一个对象,表示交易的收据信息。

在Truffle控制台中执行如下语句可以调用合约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]}]}

执行如下语句,可以调用合约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.向合约发送以太币(1)调用合约抽象的sendTransaction()函数(2)使用instance.send()函数(1)调用合约抽象的sendTransaction()函数instance.sendTransaction({...}).then(function(result){//处理交易结果});交易对象sendTransaction()函数的参数是一个表示交易对象的JSON字符串。交易对象通常包含如下参数:·from,发送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的区别2.使用TruffleDevelop的方法1.TruffleDevelop与TruffleConsole的区别·TruffleConsole可以连接到任意指定的以太坊节点;·TruffleDevelop内置一个用于开发的测试区块链,默认连接至此区块链。在如下情形下应该选择TruffleConsole:·已经安装并使用了以太坊客户端,例如Ganache或Geth。·想要将智能合约部署到测试网络或以太坊主网。因为使用TruffleConsole可以很方便的连接到指定的测试网络或以太坊主网。关于以太坊测试网络的基本情况将在第9章中介绍。·需要使用特定的网络的特定账户时,则使用TruffleConsole手动配置连接到该网络。在如下情形下应该选择TruffleDevelop:·对项目进行测试,并且不急于部署项目。·不要求使用特定的账户,只要使用测试账户即可。·不需要安装和使用独立的区块链。2.使用TruffleDevelop的方法3.Truffle命令命令具体说明build使用现有配置执行项目构建工作流compile编译智能合约config显示用户级别的配置选项console运行TruffleConsole命令行工具create创建新的合约、迁移或测试,命令格式如下:

trufflecreate<artifact_type><ArtifactName>

<artifact_type>指定要创建的对象的类型,可以是contract、migration或test;<ArtifactName>指定要创建的对象名。根据参数,trufflecreate命令会创建如下的文件:

contracts/ArtifactName.sol;

migrations/####_artifact_name.js,####代表编号和迁移脚本的标识,例如1_initial_migration.js和2_deploy_contracts.js。

tests/artifact_name.js3.Truffle命令命令具体说明debug已交互的方式调试区块链中的交易deploymigrate命令的别名,即部署合约develop运行Truffledevelop命令行工具exec在Truffle开发框架环境中执行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"}}在开发环境下,项目依赖如下插件·copy-webpack-plugin:webpack拷贝插件,用于将单个文件或整个目录复制到构建目录下。执行如下命令可以安装copy-webpack-plugin插件。npminstallcopy-webpack-plugin--save-dev·webpack:webpack插件。·webpack-cli:webpack的命令行工具。·webpack-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。·使用CopyWebpackPlugin插件将./src/index.html复制到出口文件夹dist中。·使用devServer指定webpack的开发服务器。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项目目录下执行如下命令,编译并部署合约。

trufflecompiletrufflemigrate运行项目目模板webpack中前端应用的过程浏览项目模板webpack中前端应用的页面8.3.4在Truffle框架中使用MetaMaskMetaMask是一款开源的以太坊钱包,可以用来很方便地管理自己的以太币。MetaMask可以浏览器插件的形式安装,无需安装任何客户端。1.在Chrome浏览器中安装MetaMask钱包http://metamask.io/点击Download按钮,打开下载页面Chrome网上应用店的MetaMask页面确认添加MetaMaskMetaMask的欢迎页选择钱包页面是否帮助MetaMask完善产品创建密码页面私密备份密语页面确认私密备份密语页面完成安装页面在浏览器的右上角出现扩展程序图标对MetaMask扩展程序进行授权MetaMask钱包的主界面在MetaMask钱包中选择连接的网MetaMask钱包中展示的以太坊账户及地址MetaMask钱包中的账户管理菜单2.在项目模板webpack内置的前端应用中使用MetaMask钱包单击Firefox浏览器右上方的图标,弹出下拉菜单,并选择“附加组件”,打开Firefox插件管理页面。在搜索框中输入MetaMask,然后按下回车键,可以搜索与MetaMask有关的插件。MetaMask插件详情页确认添加MetaMask插件“欢迎使用MetaMask”页面连接到Ganache测试区块链导入账户页面

Ganache测试区块链的测试账户和私钥本实例涉及下面3个账户·默认账户,即Ganache网络的第一个测试账户,用于支付转账金额。·receiver账户,在页面中Toaddress文本框中录入的账户,用于接收转账金额。·MetaMask账户,在MetaMask钱包中导入的账户,用于支付交易的Gas。导入Ganache测试账户管理连接到Ganache测试区块链的账户在项目模板webpack中前端应用的页面显示当前账户的余额确认支付交易8.3.5使用TruffleReact框架开发基于以太坊智能合约的DAppReact是FaceBook的内部项目,是用于构建用户界面的JavaScript脚本。它的特点是高性能和代码逻辑简单。开源后广受欢迎。1.React前端开发框架简介(1)引用React.js脚本<scriptcrossoriginsrc="/react@17/umd/react.development.js"></script><scriptcrossoriginsrc="/react-dom@17/umd/react-dom.development.js"></script>在生产环境下,可以通过如下方式引用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节在VisualStudioCode中安装和配置solidity插件。然后运行VisualStudioCode,在菜单中依次选择File/Folder,打开准备好的项目目录,在src子目录下创建demo.sol组件Table返回的HTML代码如下<table><tr><div><td>Hello</td><td>React</td></div></tr></table>可以将React组件存储在一个单独的js文件中。使用时可以通过import语句导入import组件名from组件js文件(5)React状态可以将React组件视为一个状态机,在与用户进行交互的过程中设置不同的状态,然后渲染UI,从而使页面与数据保持一致。换言之,在React中,如果希望渲染页面,不要直接操作DOM,只需要更新组件的状态即可。【例8-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状态的演示</h1><h2>现在是{this.state.date.toLocaleTimeString()}.</h2></div>);}}ReactDOM.render(<Clock/>,document.getElementById('box'));</script></body></html>浏览例8-3的页面2.下载项目模板react首先在/usr/local/truffle目录下创建react子目录,用于保存项目模板react。cd/usr/local/truffle/mkdirreact然后执行下面的命令下载项目模板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一个独立于当前网页在后台运行的脚本。可以用于实现离线应用,或大规模的后台数据处理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. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论