第二十六课 如何从零开始搭建一个Truffle框架的DAPP应用

发布时间:2018年10月26日 价值:20000.00 / 共识:28

1,摘要

第六课 技术小白如何开发一个DAPP区块链应用(以宠物商店为例)介绍了如何获取宠物商店的TRUFLLE框架代码,并完成部署的过程。
但是这个是已经成熟的代码框架,一般用户要开发自己的项目。那如何借用宠物商店成熟框架完成自有DAPP的搭建呢?我们以tiny熊老师的一个姓名/年龄智能合约用例来呈现方法。

2, 需求描述

我们要实现一个用户姓名和年纪的输入和呈现页面,能更新智能合约上的用户名和年龄。重新输入用户名和年纪,点击按钮可更新智能合约的这2个变量信息。

3,操作步骤

3.1 创建目录,下载框架

首先创建好目录,下载宠物商店的代码框架。

  1. duncanwang@ubuntu:~/work$ mkdir name-age
  2. duncanwang@ubuntu:~/work$ cd name-age
  3. duncanwang@ubuntu:~/work/name-age$ truffle unbox pet-shop
  4. Downloading...
  5. Unpacking...
  6. Setting up...
  7. Unbox successful. Sweet!
  8. Commands:
  9. Compile: truffle compile
  10. Migrate: truffle migrate
  11. Test contracts: truffle test
  12. Run dev server: npm run dev
  13. duncanwang@ubuntu:~/work/name-age$

3.2 创建智能合约代码

新建一个InfoContract.sol智能合约文件,并把它更新到./contracts目录下。

  1. pragma solidity ^0.4.24;
  2. contract InfoContract {
  3. string name;
  4. uint age;
  5. event Instructor(string name, uint age);
  6. function setInfo(string _name, uint _age) public {
  7. name = _name;
  8. age = _age;
  9. emit Instructor(name, age);
  10. }
  11. function getInfo() public view returns(string, uint) {
  12. return (name, age);
  13. }
  14. }

3.3 增加合约相关的部署和测试代码

1) 增加合约部署测试
文件2_info_contract.js到./migrations目录,代码如下,表示contract InfoContract合约部署。

  1. var MyContract = artifacts.require("./InfoContract.sol");
  2. module.exports = function(deployer) {
  3. // deployment steps
  4. deployer.deploy(MyContract);
  5. };

2) 增加测试文件

  1. pragma solidity ^0.4.24;
  2. import "truffle/Assert.sol";
  3. import "truffle/DeployedAddresses.sol";
  4. import "../contracts/InfoContract.sol";
  5. contract TestInfoContract {
  6. InfoContract info = InfoContract(DeployedAddresses.InfoContract());
  7. string name;
  8. uint age;
  9. function testInfo() {
  10. info.setInfo("ABC", 10);
  11. (name, age) = info.getInfo();
  12. Assert.equal(name, "ABC", "设置名字出错");
  13. Assert.equal(age, 10, "设置年龄出错");
  14. }
  15. }

3) 修改配置文件
因为默认ganache-cli的端口为8545,所以需要修改truffle.js的端口号由7545 变为8545。

  1. module.exports = {
  2. // See <http://truffleframework.com/docs/advanced/configuration>
  3. // for more about customizing your Truffle configuration!
  4. networks: {
  5. development: {
  6. host: "127.0.0.1",
  7. port: 8545,
  8. network_id: "*" // Match any network id
  9. }
  10. }
  11. };

否则测试时会有找不到客户端提示。

  1. duncanwang@ubuntu:~/work/name-age$ truffle test
  2. Could not connect to your Ethereum client. Please check that your Ethereum client:
  3. - is running
  4. - is accepting RPC connections (i.e., "--rpc" option is used in geth)
  5. - is accessible over the network
  6. - is properly configured in your Truffle configuration file (truffle.js)

3.4 验收测试智能合约

1)参考宠物商店的文章代码,在一个窗口启动一个ganache-cli 钱包。

  1. duncanwang@ubuntu:~/work/name-age$ cd ..
  2. duncanwang@ubuntu:~/work$ ganache-cli >>trace.log

2)编译智能合约
然后启动另外一个窗口命令行,输入一下命令。

  1. duncanwang@ubuntu:~/work/name-age$ truffle compile
  2. Compiling ./contracts/InfoContract.sol...
  3. Compiling ./contracts/Migrations.sol...
  4. Writing artifacts to ./build/contracts

智能合约验收命令。

测试成功的提示说明:

  1. duncanwang@ubuntu:~/work/name-age$ truffle test
  2. Using network 'development'.
  3. Compiling ./contracts/InfoContract.sol...
  4. Compiling ./test/TestInfoContract.sol...
  5. Compiling truffle/Assert.sol...
  6. Compiling truffle/DeployedAddresses.sol...
  7. Compilation warnings encountered:
  8. /home/duncanwang/work/name-age/test/TestInfoContract.sol:12:4: Warning: No visibility specified. Defaulting to "public".
  9. function testInfo() {
  10. ^ (Relevant source part starts here and spans across multiple lines).
  11. TestInfoContract
  12. testInfo (838ms)
  13. 1 passing (5s)

3.5 完成前端页面

完成以下2个文件的修改更新和上传。
1) index.html
把宠物商店的index.html的代码删除,替换为本文需要的框架代码。

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <meta http-equiv="X-UA-Compatible" content="ie=edge">
  7. <title>First Truffle DApp Demo</title>
  8. <link rel="stylesheet" type="text/css" href="main.css">
  9. </head>
  10. <body>
  11. <div class="container">
  12. <h1> First Truffle DApp Demo</h1>
  13. <h2 id="info"></h2>
  14. <img id="loader" src="https://loading.io/spinners/double-ring/lg.double-ring-spinner.gif">
  15. <label for="name" class="col-lg-2 control-label">姓名:</label>
  16. <input id="name" type="text">
  17. <label for="name" class="col-lg-2 control-label">年龄:</label>
  18. <input id="age" type="text">
  19. <button id="button">更新</button>
  20. </div>
  21. <script src="http://libs.baidu.com/jquery/2.1.1/jquery.min.js"></script>
  22. <script src="js/web3.min.js"></script>
  23. <script src="js/truffle-contract.js"></script>
  24. <script src="js/app.js"></script>

2) app.js
然后修改app.js的代码,完成智能合约的执行和调用作用。

  1. App = {
  2. web3Provider: null,
  3. contracts: {},
  4. init: function() {
  5. return App.initWeb3();
  6. },
  7. /*加载web3*/
  8. initWeb3: function() {
  9. if (typeof web3 !== 'undefined') {
  10. App.web3Provider = web3.currentProvider
  11. web3 = new Web3(App.web3Provider);
  12. } else {
  13. App.web3Provider = new Web3.providers.HttpProvider("http://localhost:9545")
  14. web3 = new Web3(App.web3Provider);
  15. }
  16. return App.initContract();
  17. },
  18. /*初始化合约,获取合约,不需要使用at()的方式;
  19. 显示合约的姓名和年龄信息*/
  20. initContract: function() {
  21. $.getJSON('InfoContract.json', function(data){
  22. App.contracts.InfoContract = TruffleContract(data);
  23. App.contracts.InfoContract.setProvider(App.web3Provider);
  24. App.getInfo();
  25. App.watchChanged();
  26. });
  27. App.bindEvents();
  28. },
  29. getInfo: function() {
  30. App.contracts.InfoContract.deployed().then(function(instance) {
  31. return instance.getInfo.call();
  32. }).then(function(result) {
  33. $("#loader").hide();
  34. $("#info").html(result[0]+' ('+result[1]+' years old)');
  35. console.log(result);
  36. }).catch(function(err) {
  37. console.error(err);
  38. });
  39. },
  40. /*点击按钮更新姓名和年龄,则需要更新到智能合约上*/
  41. bindEvents: function() {
  42. $("#button").click(function() {
  43. $("#loader").show();
  44. App.contracts.InfoContract.deployed().then(function(instance) {
  45. return instance.setInfo($("#name").val(), $("#age").val(), {gas: 500000});
  46. }).then(function(result) {
  47. return App.getInfo();
  48. } ).catch(function(err) {
  49. console.error(err);
  50. });
  51. });
  52. },
  53. watchChanged: function() {
  54. App.contracts.InfoContract.deployed().then(function(instance) {
  55. var infoEvent = instance.Instructor();
  56. return infoEvent.watch(function(err, result) {
  57. $("#loader").hide();
  58. $("#info").html(result.args.name +' ('+ result.args.age +' years old)');
  59. });
  60. });
  61. }
  62. }
  63. $(function(){
  64. $(window).load(function() {
  65. App.init();
  66. });
  67. });

3.6 测试验收前端和合约交互代码

1) 部署合约
合约部署成功。

  1. duncanwang@ubuntu:~/work/name-age$ truffle migrate
  2. Using network 'development'.
  3. Running migration: 1_initial_migration.js
  4. Deploying Migrations...
  5. ... 0x5b3cd41a7fa7c58361172ac797412469a10edfbe721d8d81988f19282c9cb6e4
  6. Migrations: 0x92b6ecd23aa98fad36926c12ec701f9aaa0933f4
  7. Saving successful migration to network...
  8. ... 0x826fcd5b72b48435bf4f9941305727e52b0b7290631ba7b39f642027b1ee6947
  9. Saving artifacts...
  10. Running migration: 2_info_contract.js
  11. Deploying InfoContract...
  12. ... 0x9943dd7b90207bd9fd1e85524d1d0227f18a92269d73f5a2141cb71c22dda1e9
  13. InfoContract: 0x191391c710e1b632e40b4f2267dbc0f3bdb2bed4
  14. Saving successful migration to network...
  15. ... 0x7e11f6e32585524e338e73439e4026c7c766625e5d23d56a4c90f8a11e5001ed
  16. Saving artifacts...

2)安装并启动lite-server
1] 安装lite-server
【定义】lite-server 是轻量级的,仅适用于开发 的 node 服务器, 它仅支持 web app。 它能够为你打开浏览器, 当你的html或是JavaScript文件变化时,它会识别到并自动帮你刷新浏览器, 还能使用套接字自动注入变化的CSS, 当路由没有被找到时,它将自动后退页面。
参考第一课 如何在WINDOWS环境下搭建以太坊开发环境,完成MetaMask和liteServer的安装。

duncanwang@ubuntu:~/work/name-age$ npm install lite-server —save-dev

成功安装的输出结果如下:

  1. npm WARN pet-shop@1.0.0 No description
  2. npm WARN pet-shop@1.0.0 No repository field.
  3. npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.2.4 (node_modules/fsevents):
  4. npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.4: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"ia32"})
  5. + lite-server@2.4.0
  6. added 342 packages from 273 contributors in 56.82s

2] 在新的窗口完成lite-server的启动。

  1. duncanwang@ubuntu:~/work/name-age$ npm run dev
  2. > pet-shop@1.0.0 dev /home/duncanwang/work/name-age
  3. > lite-server
  4. ** browser-sync config **
  5. { injectChanges: false,
  6. files: [ './**/*.{html,htm,css,js}' ],
  7. watchOptions: { ignored: 'node_modules' },
  8. server:
  9. { baseDir: [ './src', './build/contracts' ],
  10. middleware: [ [Function], [Function] ] } }
  11. [Browsersync] Access URLs:
  12. --------------------------------------
  13. Local: http://localhost:3000
  14. External: http://10.225.18.149:3000
  15. --------------------------------------
  16. UI: http://localhost:3001
  17. UI External: http://localhost:3001
  18. --------------------------------------
  19. [Browsersync] Serving files from: ./src
  20. [Browsersync] Serving files from: ./build/contracts
  21. [Browsersync] Watching files...

3) 打开主页
输入lite-server提示的主页地址:http://10.225.18.149:3000
可以看到页面输出信息。

image.png

4)更新姓名和年龄
输入框输入姓名和年龄:王登辉,18 ,点击更新按钮,会弹出MEATMASK的交易提示,确认交易。
image.png

确认交易后,姓名和年龄信息会更新。

4,总结

本文仅从操作层面讲解了如何利用宠物商店的模板样例,快速重构一个含前端的DAPP页面。
具体WEB.3J的接口函数及定义,参考文章《第十一课 从宠物商店案例看DAPP架构和WEB3.JS交互接口》
所有工程的源码已上传到知识星球,有需要的同学可加入下载。

  • 分享 收藏
0 条评论
  • 这篇文章暂无评论,赶紧评论一下吧~