美文网首页HiBlock区块链社区
如何从零开始搭建一个Truffle框架的DAPP应用

如何从零开始搭建一个Truffle框架的DAPP应用

作者: 宇宙永恒 | 来源:发表于2018-11-13 23:39 被阅读5次
    image

    1

    摘要

    开发实战|3步教你在以太坊上开一家宠物店(附流程+代码)介绍了如何获取宠物商店的TRUFLLE框架代码,并完成部署的过程。

    但是这个是已经成熟的代码框架,一般用户要开发自己的项目。那如何借用宠物商店成熟框架完成自有DAPP的搭建呢?我们以tiny熊老师的一个姓名/年龄智能合约用例来呈现方法。

    2

    需求描述

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

    3

    操作步骤

    3.1 创建目录,下载框架

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

    duncanwang@ubuntu:~/work$ mkdir name-age
    
    duncanwang@ubuntu:~/work$ cd name-age
    
    duncanwang@ubuntu:~/work/name-age$ truffle unbox pet-shop
    
    Downloading...
    
    Unpacking...
    
    Setting up...
    
    Unbox successful. Sweet!
    
    Commands:
    
      Compile:        truffle compile
    
      Migrate:        truffle migrate
    
      Test contracts: truffle test
    
      Run dev server: npm run
    
     devduncanwang@ubuntu:~/work/name-age$
    

    3.2 创建智能合约代码

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

    pragma solidity ^0.4.24;
    
    contract InfoContract {
    
        string name;
    
        uint age;
    
        event Instructor(string name, uint age);
    
        function setInfo(string _name, uint _age) public {
    
            name = _name;
    
            age = _age;
    
            emit Instructor(name, age);
    
        } 
    
       function getInfo() public view returns(string, uint) {
    
            return (name, age);
    
        }
    
    }
    

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

    1) 增加合约部署测试

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

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

    2) 增加测试文件

    pragma solidity ^0.4.24;
    
    import "truffle/Assert.sol";
    
    import "truffle/DeployedAddresses.sol";
    
    import "../contracts/InfoContract.sol";
    
    contract TestInfoContract {
    
       InfoContract info = InfoContract(DeployedAddresses.InfoContract());
    
       string name;
    
       uint age;
    
       function testInfo() {
    
         info.setInfo("ABC", 10);
    
         (name, age) = info.getInfo();
    
         Assert.equal(name, "ABC", "设置名字出错");
    
         Assert.equal(age, 10, "设置年龄出错");
    
       }
    
    }
    

    3)修改配置文件

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

    module.exports = {
    
      // See <http://truffleframework.com/docs/advanced/configuration>
    
      // for more about customizing your Truffle configuration!
    
      networks: {
    
        development: {
    
          host: "127.0.0.1",
    
          port: 8545,
    
          network_id: "*" // Match any network id
    
        }
    
      }
    
    };
    

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

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

    3.4 验收测试智能合约

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

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

    2)编译智能合约

    然后启动另外一个窗口命令行,输入一下命令。

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

    3)智能合约验收命令。

    测试成功的提示说明:

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

    3.5 完成前端页面

    完成以下2个文件的修改更新和上传。

    1) index.html

    把宠物商店的index.html的代码删除,替换为本文需要的框架代码。

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

    2) app.js

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

    App = {
    
      web3Provider: null,
    
      contracts: {}, 
    
     init: function() {
    
        return App.initWeb3(); 
    
     },
    
    /*加载web3*/
    
      initWeb3: function() {
    
        if (typeof web3 !== 'undefined') {
    
             App.web3Provider = web3.currentProvider
    
             web3 = new Web3(App.web3Provider);
    
         } else {
    
             App.web3Provider = new Web3.providers.HttpProvider("http://localhost:9545") 
    
            web3 = new Web3(App.web3Provider);
    
         }
    
         return App.initContract();
    
      },
    
    /*初始化合约,获取合约,不需要使用at()的方式;
    
      显示合约的姓名和年龄信息*/
    
      initContract: function() {
    
        $.getJSON('InfoContract.json', function(data){
    
          App.contracts.InfoContract = TruffleContract(data); 
    
         App.contracts.InfoContract.setProvider(App.web3Provider);
    
          App.getInfo();
    
          App.watchChanged();
    
        });
    
        App.bindEvents();
    
      },  
    
    getInfo: function() {
    
        App.contracts.InfoContract.deployed().then(function(instance) {
    
          return instance.getInfo.call();
    
        }).then(function(result) { 
    
         $("#loader").hide();
    
          $("#info").html(result[0]+' ('+result[1]+' years old)'); 
    
         console.log(result);
    
        }).catch(function(err) {
    
          console.error(err); 
    
       });
    
      },
    
    /*点击按钮更新姓名和年龄,则需要更新到智能合约上*/
    
      bindEvents: function() {
    
        $("#button").click(function() { 
    
           $("#loader").show();
    
            App.contracts.InfoContract.deployed().then(function(instance) {
    
              return instance.setInfo($("#name").val(), $("#age").val(), {gas: 500000}); 
    
           }).then(function(result) {
    
              return App.getInfo();
    
            } ).catch(function(err) {
    
              console.error(err);
    
            }); 
    
         });
    
      }, 
    
     watchChanged: function() { 
    
       App.contracts.InfoContract.deployed().then(function(instance) { 
    
         var infoEvent = instance.Instructor(); 
    
         return infoEvent.watch(function(err, result) {
    
            $("#loader").hide();
    
            $("#info").html(result.args.name +' ('+ result.args.age +' years old)'); 
    
         }); 
    
       });
    
      }
    
      }
    
    $(function(){  
    
    $(window).load(function() {
    
          App.init();
    
      });
    
    });
    

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

    1) 部署合约

    合约部署成功。

    duncanwang@ubuntu:~/work/name-age$ truffle migrate
    
    Using network 'development'.
    
    Running migration: 1_initial_migration.js
    
      Deploying Migrations...
    
      ... 0x5b3cd41a7fa7c58361172ac797412469a10edfbe721d8d81988f19282c9cb6e4
    
      Migrations: 0x92b6ecd23aa98fad36926c12ec701f9aaa0933f4
    
    Saving successful migration to network...
    
      ... 0x826fcd5b72b48435bf4f9941305727e52b0b7290631ba7b39f642027b1ee6947
    
    Saving artifacts...
    
    Running migration: 2_info_contract.js
    
      Deploying InfoContract...
    
      ... 0x9943dd7b90207bd9fd1e85524d1d0227f18a92269d73f5a2141cb71c22dda1e9
    
      InfoContract: 0x191391c710e1b632e40b4f2267dbc0f3bdb2bed4
    
    Saving successful migration to network...
    
      ... 0x7e11f6e32585524e338e73439e4026c7c766625e5d23d56a4c90f8a11e5001ed
    
    Saving artifacts...
    

    2)安装并启动lite-server

    1] 安装lite-server

    【定义】lite-server 是轻量级的,仅适用于开发 的 node 服务器, 它仅支持 web app。 它能够为你打开浏览器, 当你的html或是JavaScript文件变化时,它会识别到并自动帮你刷新浏览器, 还能使用套接字自动注入变化的CSS, 当路由没有被找到时,它将自动后退页面。

    参考:如何在WINDOWS环境下搭建以太坊开发环境(https://www.jianshu.com/p/683ea7d62a39),完成MetaMask和liteServer的安装。

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

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

    npm WARN pet-shop@1.0.0 No description
    
    npm WARN pet-shop@1.0.0 No repository field.
    
    npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.2.4 (node_modules/fsevents):
    
    npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.4: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"ia32"})
    
    + lite-server@2.4.0
    
    added 342 packages from 273 contributors in 56.82s
    
    **2] 在新的窗口完成lite-server的启动。**
    
    duncanwang@ubuntu:~/work/name-age$ npm run dev
    
    > pet-shop@1.0.0 dev /home/duncanwang/work/name-age
    
    > lite-server
    
    ** browser-sync config **
    
    { injectChanges: false,
    
      files: [ './**/*.{html,htm,css,js}' ],
    
      watchOptions: { ignored: 'node_modules' },
    
      server:
    
        { baseDir: [ './src', './build/contracts' ],
    
         middleware: [ [Function], [Function] ] } }
    
    [Browsersync] Access URLs:
    
     --------------------------------------
    
           Local: http://localhost:3000
    
        External: http://10.225.18.149:3000
    
     --------------------------------------
    
              UI: http://localhost:3001
    
     UI External: http://localhost:3001
    
     --------------------------------------
    
    [Browsersync] Serving files from: ./src
    
    [Browsersync] Serving files from: ./build/contracts
    
    [Browsersync] Watching files...
    

    3)打开主页

    输入lite-server提示的主页地址:http://10.225.18.149:3000

    可以看到页面输出信息。

    image

    4)更新姓名和年龄

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

    image

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

    image

    4

    总结

    本文仅从操作层面讲解了如何利用宠物商店的模板样例,快速重构一个含前端的DAPP页面。

    具体WEB.3J的接口函数及定义,参考文章《从宠物商店案例看DAPP架构和WEB3.JS交互接口》。

    所有工程的源码已上传到知识星球,有需要的同学可加入下载。

    image

    本文作者:HiBlock区块链技术布道群-辉哥

    原文发布于简书

    加微信baobaotalk_com,加入技术布道群

    image

    相关文章

      网友评论

        本文标题:如何从零开始搭建一个Truffle框架的DAPP应用

        本文链接:https://www.haomeiwen.com/subject/kpwrfqtx.html