前面我们基于Embark Demo[1]?介绍了 Embark 框架,今天使用 Embark 来实实在在开发一个 DApp:从零开发开发一个投票DApp。
通过本文可以学习到: 1.使用 Embark 创建项目2.利用 EmbarkJS 与合约交互3.Embark 如果部署合约到主网(利用Infura节点)
创建Embark项目 >?embark?new?embark-election 会在当前目录下生成一个 embark-election 目录,并创建好了相应的项目框架文件:如:?app/、contracts/、config/、embark.json等。 我们需要在对应的目录中,添加相应的实现。 编写合约 在contracts/中添加合约Election.sol: pragma?solidity?^0.6.0;contract?Election?{????//?Model?a?Candidate????struct?Candidate?{????????uint?id;????????string?name;????????uint?voteCount;????}????mapping(address?=>?bool)?public?voters;????mapping(uint?=>?Candidate)?public?candidates;????//?Store?Candidates?Count????uint?public?candidatesCount;????//?voted?event????event?votedEvent?(????????uint?indexed?_candidateId????);????constructor?()?public?{????????addCandidate("Tiny?熊");????????addCandidate("LearnBlockChain.cn");????}????function?addCandidate?(string?memory?_name)?private?{????????candidatesCount?++;????????candidates[candidatesCount]?=?Candidate(candidatesCount,?_name,?0);????}????function?vote?(uint?_candidateId)?public?{????????//?require?that?they?haven't?voted?before????????require(!voters[msg.sender]);????????//?require?a?valid?candidate????????require(_candidateId?>?0?&&?_candidateId?<=?candidatesCount);????????//?record?that?voter?has?voted????????voters[msg.sender]?=?true;????????//?update?candidate?vote?Count????????candidates[_candidateId].voteCount?++;????????//?trigger?voted?event????????emit?votedEvent(_candidateId);????}} 之前有使用过Truffle开发过投票DApp[3],合约的代码完全一样,就不在解释。 Embark 合约编译部署 Embark 合约部署的配置在?config/contracts.js, 在?deploy?字段加入 Election 合约: deploy:?{??????Election:?{??????}????} 现在运行?embark run?, Embark 会自动编译及部署Election.sol到?config/blockchain.js?配置的?development?网络。
blockchain.js?中?development?网络是使用 ganache-cli 启动的网络,其配置如下: development:?{????client:?'ganache-cli',????clientConfig:?{??????miningMode:?'dev'?????}??} embark启动后,我们可以在 COCKPIT 或 DashBoard 看到Election.sol合约的部署日志,大概类似下面: deploying?Election?with?351122?gas?at?the?price?of?1?Wei,?estimated?cost:?351122?Wei?(txHash:?0x9da4dfb951149...d5c306dcabf300a4)Election?deployed?at?0x10C257c76Cd3Dc35cA2618c6137658bFD1fFCcfA?using?346374?gas?(txHash:?0x9da4dfb951149ea4...d5c306dcabf300a4)finished?deploying?contracts 编写前端代码 Embark Artifacts Embark提供了一个 EmbarkJS的JavaScript库,来帮助开发者和合约进行交互。 在使用web3.js 时,和合约交互需要知道合约的ABI及地址来创建JS环境中对应的合约对象,一般代码是这样的: //?需要ABI及地址创建对象var?myContract?=?new?web3.eth.Contract([...ABI...],?'0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe'); Embark 在编译部署后,每个合约会生成一个对应的构件Artifact(可以在embarkArtifacts/contracts/?目录下找的这些文件),我们可以直接使用?Artifact?生成的合约对象调用合约。 一个构件通常会包含:合约的ABI、部署地址、启动代码及其他的配置数据。 查看一下Election.sol?对应的构件Election.js?代码就更容易理解: import?EmbarkJS?from?'../embarkjs';let?ElectionJSONConfig?=?{"contract_name":"Election","address":"0x10C257c76Cd3Dc35cA2618c6137658bFD1fFCcfA","code":"...",?...?,"abiDefinition":[...]};let?Election?=?new?EmbarkJS.Blockchain.Contract(ElectionJSONConfig);export?default?Election; Election.js?最后一行导出了一个与合约同名的JavaScript 对象,下面看看怎么使用这个对象。 修改前端index.html 在使用embark new embark-election创建项目时, 前端目录app/下生成了一个?index.html: <html>??<head>????<title>Embark</title>????<link?rel="stylesheet"?href="css/app.css">??????<script?src="js/app.js"></script>??</head>??<body>????<h3>Welcome?to?Embark!</h3>??</body></html> 这里有一个地方需要注意一下,第5 6行引入了?css/app.css,?js/app.js,而其实app/下并没有这两个文件,这两个文件其实是按照?embark.json?配置的规程生成的。 embark.json?关于前端的配置如下: "app":?{????"css/app.css":?["app/css/**"],????"js/app.js":?["app/js/index.js"],????"images/":?["app/images/**"],????"index.html":?"app/index.html"??}, "css/app.css": ["app/css/**"]?表示所有在app/css/目录下的文件会被压缩到 dist目录的?css/app.css?,app/js/index.js则会编译为js/app.js,其他的配置类似。
接下来修改前端部分的代码,主要是在index.html的body加入一个table显示候选人,以及加入一个投票框,代码如下(节选): <table?class="table">??<thead>????<tr>??????<th?scope="col">#</th>??????<th?scope="col">候选人</th>??????<th?scope="col">得票数</th>????</tr>??</thead>??<tbody?id="candidatesResults">??</tbody></table><div?class="form-group"><label?for="candidatesSelect">选择候选人</label><select?class="form-control"?id="candidatesSelect"></select></div> 前端,我们使用了 bootstrap css ,把文件拷贝到app/css目录下,接下来,看看关键的一步:前端如何与与合约交互。 使用 Artifacts与合约交互 EmbarkJS 连接 Web3 创建项目时生成的app/js/index.js?生成了如下代码: import?EmbarkJS?from?'Embark/EmbarkJS';EmbarkJS.onReady((err)?=>?{??//?You?can?execute?contract?calls?after?the?connection}); 这段代码里,EmbarkJS为我们准备了一个onReady回调函数,这是因为EmbarkJS会自动帮我们完成与web3节点的连接与初始化,当这些就绪后(调用onReady),前端就可以和链进行交互了。 大家也许会好奇EmbarkJS怎么知道我们需要连接那个节点呢?其实在config/contracts.js?有一个?dappConnection?配置项: dappConnection:?[??"$EMBARK",??"$WEB3",??//?使用浏览器注入的web3,?如MetaMask等??"ws://localhost:8546",??"http://localhost:8545"], $EMBARK?: 是Embark在DApp和节点之前实现的一个代理,使用$EMBARK有几个好处: 1.可以在config/blockchain.js?配置于DApp交互的账号?accounts。2.可以更友好的的看到交易记录。 EmbarkJS 会从上到下,依次尝试?dappConnection提供的连接,如果有一个可以连接上,就会停止尝试。 获取合约数据渲染界面 当 EmbarkJS 环境准备 onReady后,就可以使用构件Election.js获取合约数据,如获取调用合约获取候选人数量: import?EmbarkJS?from?'Embark/EmbarkJS';import?Election?from?'../../embarkArtifacts/contracts/Election.js';EmbarkJS.onReady((err)?=>?{????Election.methods.candidatesCount().call().then(count?=>?console.log("?candidatesCount:?"?+?count);????);}); 代码中直接使用构件导出的Election对象,调用合约方法?Election.methods.candidatesCount().call(), 调用合约方法与web3.js 一致。 了解了如何与合约交互,接下来渲染界面就简单了,我们把代码整理下,分别定义3个函数:?App.getAccount()、App.render()、App.onVote()?来获取当前账号(需要用来判断哪些账号投过票)、界面渲染、处理点击投标。 EmbarkJS.onReady((err)?=>?{??App.getAccount();??App.render();??App.onVote();}); App.getAccount()?的实现如下: import?"./jquery.min.js"var?App?=?{??account:?null,??getAccount:?function()?{????web3.eth.getCoinbase(function(err,?account)?{??????if?(err?===?null)?{????????App.account?=?account;????????console.log(account);????????$("#accountAddress").html("Your?Account:?"?+?account);??????}????})??},??} 在代码中,我们直接使用了web3对象,就是因为EmbarkJS帮我们进行了web3的初始化。另外,我们引入jquery.min.js?来进行UI界面的渲染。 App.render()?的实现(主干)如下: render:?function?()?{????Election.methods.candidatesCount().call().then(??????candidatesCount?=>???????{????????var?candidatesResults?=?$("#candidatesResults");????????var?candidatesSelect?=?$('#candidatesSelect');????????for?(var?i?=?1;?i?<=?candidatesCount;?i++)?{??????????Election.methods.candidates(i).call().then(function(candidate)?{????????????var?id?=?candidate[0];????????????var?name?=?candidate[1];????????????var?voteCount?=?candidate[2];????????????//?Render?candidate?Result????????????var?candidateTemplate?=?"<tr><th>"?+?id?+?"</th><td>"?+?name?+?"</td><td>"?+?voteCount?+?"</td></tr>";????????????candidatesResults.append(candidateTemplate);????????????//?Render?candidate?ballot?option????????????var?candidateOption?=?"<option?value='"?+?id?+?"'?>"?+?name?+?"</?option>";????????????candidatesSelect.append(candidateOption);??????????});????????}??????});??} App.onVote()?的实现(主干)如下: onVote:?function()?{????$("#vote").click(function(e){??????var?candidateId?=?$('#candidatesSelect').val();??????Election.methods.vote(candidateId).send()??????.then(function(result)?{????????App.render();??????}).catch(function(err)?{????????console.error(err);??????});????});??} 部署 使用?embark run?时,会为我们启动一个Geth 或?ganache-cli?的本地网络部署合约,以及在8000端口上启用一个本地服务器来部署前端应用,我们在浏览器输入http://localhost:8000/?就可以看到DApp界面,如图: 当我们的DApp 在测试环境通过后,就可以部署到以太坊的主网。 利用Infura部署到主网 要部署到主网,需要在blockchain.js?中添加一个主网网络,这里以测试网Ropsten网络为例: ropsten:?{????endpoint:?"https://ropsten.infura.io/v3/d3fe47c...4f",????accounts:?[??????{????????mnemonic:?"?你的助记词?",????????hdpath:?"m/44'/60'/0'/0/",????????numAddresses:?"1"??????}????]??} 如果我们没有自己的主网节点,可以使用 endpoint 来指向以个外部节点,最常用的就是Infura[4]。 添加好配置之后,使用build命令来构建主网发布版本: embark?build?ropsten??#?最后是网络参数 所有的文件在生成在dist目录下,把他们部署到线上服务器就完成了部署。也可以使用embark upload ropsten?上传到IPFS。 References [1]?Embark Demo:?https://learnblockchain.cn/article/566 —- 编译者/作者:深入浅出区块链技 玩币族申明:玩币族作为开放的资讯翻译/分享平台,所提供的所有资讯仅代表作者个人观点,与玩币族平台立场无关,且不构成任何投资理财建议。文章版权归原作者所有。 |
教程:使用Embark开发投票DApp
2020-02-27 深入浅出区块链技 来源:区块链网络
LOADING...
相关阅读:
- 基于DeFi的流动性挖矿Yield Farming2020-08-01
- DFS结束了,被小割了一些柚子,以后应该涨涨记性了2020-08-01
- Filecoin挖矿指南之设备性能对证明计算的影响2020-08-01
- 三少解币:8.1BTC再破新高日内涨幅仍在蓄力2020-08-01
- 周末BTC连破多个整数关口强势上涨动能强劲逼空行情进行到底/8月1日币2020-08-01