美文网首页
truffle创建DAPP项目

truffle创建DAPP项目

作者: 狂侠天骄 | 来源:发表于2018-10-17 23:19 被阅读0次

    一、智能合约的创建与测试

    1、创建项目

    truffle init
    
    生成的目录如下:

    2、编写智能合约Adoption.sol

    pragma solidity ^0.4.17;
    
    contract Adoption {
    address[16] public adopters;
    function adopt(uint petId) public returns (uint) {
        require(petId>=0 && petId <= 15);
        adopters[petId] = msg.sender;
        return petId;
    }
    
    function getAdopters() public view returns (address[16]) {
        return adopters;
    }
    }
    

    注:这里没写构造函数,会自动生成。

    3、编译合约

    在项目根目录下执行:truffle compile,然后会生成一个build文件夹,里面是编译成的Adoption.json文件
    

    4、在migration目录下创建部署文件

    var Adoption = artifacts.require("Adoption");  //这里填入的是合约名,而不是文件名
    
    module.exports = function(deployer) {
    deployer.deploy(Adoption);
    };
    

    5、打开ganache(区块链的运行环境)

    6、配置truffle.js文件

    module.exports = {
    networks: {
    development: {
      host: "127.0.0.1",        //ganache网络的地址
      port: 7545,                  //ganache的监听端口
      network_id: "*"    // Match any network id
    }
    }
    };
    

    注意:该配置是为了让truffle连接ganache为我们准备的区块链网络。
    注意:查看合约编译生成的文件Adoption.json,里面的"networks":配置为空。

    7、部署合约

    truffle migrate
    
    执行后查看Adoption.json,这时网络信息已经加上去了:
    "networks": {
    "5777": {
      "events": {},
      "links": {},
      "address": "0x345ca3e014aaf5dca488057592ee47305d9b3e10",
      "transactionHash": "0x0ec。。。"
    }
    

    },

    8、这时查看ganache信息的block已经不再是0了。

    9、编写测试合约(在test目录下创建TestAdoption.sol)

    pragma solidity ^0.4.17;
    
    import 'truffle/Assert.sol';
    import 'truffle/DeployedAddresses.sol';  //用于获取部署合约的地址
    import '../contracts/Adoption.sol';
    
    contract TestAdoption {
        Adoption adoption = Adoption(DeployedAddresses.Adoption());
    
    function testUserCanAdoptPet() public {
        uint returnedId = adoption.adopt(8);
        uint expected = 8;
        Assert.equal(returnedId, expected, "Aoption of pet Id 8 should be recorded.");
    }
    
    function testGetAdopterAddressByPetid() public {
        address expected = this;
        address adopter = adoption.adopters(8);
    
        Assert.equal(adopter, expected, "Owner of pet ID 8 should be recorded.");
    }
    
    function testGetAdopterAddressByPetIdInArray() public {
    
        address expected = this;
    
        address[16] memory adopters = adoption.getAdopters();   //返回领养者的地址
        Assert.equal(adopters[8], expected, "Owner of Pet Id 8 should be recoded.");
    }
    }
    

    10、测试

     在终端运行:truffle test。运行如下图所示,表示三个测试方法都通过了:
    

    这时去查看ganache,发现多了很多交易,也打包了一些区块,说明测试过程也有很多交易产生。

    二、初始化web环境

    11、将项目转为npm工程

      终端执行npm init
    

    这一步执行完后会生成package.json文件,可用于显示工程的信息,也可以用于管理一些依赖。

    12、提供一个web服务器

    npm install lite-server
    注:我通过这种方式安装失败,然后通过npm install lite-server --save-dev安装成功
    

    13、新建一个src文件夹,用于存储web应用的源文件

    14、配置服务器信息

     根目录下创建bs-config.json文件,如下:
    {
      "port": 8000,          //这个端口要不指定,则会有个默认端口
    "server": {
        "baseDir": ["./src", "./build/contracts"]
         }
    }
    

    15、package.json文件中加入红框行

    表示:在运行这个脚本命令时运行起server

    16、在src目录下创建文件index.html,内容如下:

    Hello Pet-shop
    

    17、在终端运行

    npm run dev
    运行完之后会自动打开一个浏览器,输出 index.html中的内容Hello Pet-shop,如下所示:
    

    18、页面编写

    在上面创建的src目录中,完全拷贝从truffle unbox出来的pet-shop项目的src目录(css、fonts、images、js、pets.json等)。

    19、编辑index.html,内容如下:

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <title>Pete's Pet Shop</title>
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link href="css/bootstrap.min.css" rel="stylesheet">
    </head>
    
    <body>
        <div class="container">
            <h1 class="text-center">Pete's Pet Shop</h1>
            <div id="petsRow" class="row"></div>
        </div>
    
        <div id="petTemplate" style="display: none">
            <div class="col-sm-6 col-md-4 col-lg-3">
              <div class="panel panel-default panel-pet">
                <div class="panel-heading">
                  <h3 class="panel-title">Scrappy</h3>
                </div>
                <div class="panel-body">
                  <img alt="140x140" data-src="holder.js/140x140"
                   class="img-rounded img-center" style="width: 100%;" src="" data-holder-rendered="true">
                  <br/><br/>
                  <strong>Breed</strong>: <span class="pet-breed">Golden Retriever</span><br/>
                  <strong>Age</strong>: <span class="pet-age">3</span><br/>
                  <strong>Location</strong>: <span class="pet-location">Warren, MI</span><br/><br/>
                  <button class="btn btn-default btn-adopt" type="button" data-id="0">Adopt</button>
                </div>
              </div>
            </div>
          </div>
    
          <!-- 官方的代码中引入谷歌的库,但是谷歌被墙了 -->
          <script src="http://libs.baidu.com/jquery/1.9.1/jquery.min.js"></script>
          <script src="js/bootstrap.min.js"></script>
          <!-- 下面的两个库是要和智能合约进行交互的,truffle-contract是web3的包装,有高级一点的js的用法 -->
          <script src="js/web3.min.js"></script>
          <script src="js/truffle-contract.js"></script>
    
          <script src="js/app.js"></script>
    </body>
    </html>
    

    20、编辑pets.json文件,内容如下:

    [
      {
        "id": 0,
        "name": "Frieda",
        "picture": "images/scottish-terrier.jpeg",
        "age": 3,
        "breed": "Scottish Terrier",
        "location": "Lisco, Alabama"
      },
      {
        "id": 1,
        "name": "Gina",
        "picture": "images/scottish-terrier.jpeg",
        "age": 3,
        "breed": "Scottish Terrier",
        "location": "Tooleville, West Virginia"
      },
      {
        "id": 2,
        "name": "Collins",
        "picture": "images/french-bulldog.jpeg",
        "age": 2,
        "breed": "French Bulldog",
        "location": "Freeburn, Idaho"
      },
      {
        "id": 3,
        "name": "Melissa",
        "picture": "images/boxer.jpeg",
        "age": 2,
        "breed": "Boxer",
        "location": "Camas, Pennsylvania"
      },
      {
        "id": 4,
        "name": "Jeanine",
        "picture": "images/french-bulldog.jpeg",
        "age": 2,
        "breed": "French Bulldog",
        "location": "Gerber, South Dakota"
      },
      {
        "id": 5,
        "name": "Elvia",
        "picture": "images/french-bulldog.jpeg",
        "age": 3,
        "breed": "French Bulldog",
        "location": "Innsbrook, Illinois"
      },
      {
        "id": 6,
        "name": "Latisha",
        "picture": "images/golden-retriever.jpeg",
        "age": 3,
        "breed": "Golden Retriever",
        "location": "Soudan, Louisiana"
      },
      {
        "id": 7,
        "name": "Coleman",
        "picture": "images/golden-retriever.jpeg",
        "age": 3,
        "breed": "Golden Retriever",
        "location": "Jacksonwald, Palau"
      },
      {
        "id": 8,
        "name": "Nichole",
        "picture": "images/french-bulldog.jpeg",
        "age": 2,
        "breed": "French Bulldog",
        "location": "Honolulu, Hawaii"
      },
      {
        "id": 9,
        "name": "Fran",
        "picture": "images/boxer.jpeg",
        "age": 3,
        "breed": "Boxer",
        "location": "Matheny, Utah"
      },
      {
        "id": 10,
        "name": "Leonor",
        "picture": "images/boxer.jpeg",
        "age": 2,
        "breed": "Boxer",
        "location": "Tyhee, Indiana"
      },
      {
        "id": 11,
        "name": "Dean",
        "picture": "images/scottish-terrier.jpeg",
        "age": 3,
        "breed": "Scottish Terrier",
        "location": "Windsor, Montana"
      },
      {
        "id": 12,
        "name": "Stevenson",
        "picture": "images/french-bulldog.jpeg",
        "age": 3,
        "breed": "French Bulldog",
        "location": "Kingstowne, Nevada"
      },
      {
        "id": 13,
        "name": "Kristina",
        "picture": "images/golden-retriever.jpeg",
        "age": 4,
        "breed": "Golden Retriever",
        "location": "Sultana, Massachusetts"
      },
      {
        "id": 14,
        "name": "Ethel",
        "picture": "images/golden-retriever.jpeg",
        "age": 2,
        "breed": "Golden Retriever",
        "location": "Broadlands, Oregon"
      },
      {
        "id": 15,
        "name": "Terry",
        "picture": "images/golden-retriever.jpeg",
        "age": 2,
        "breed": "Golden Retriever",
        "location": "Dawn, Wisconsin"
      }
    ]
    

    21、这时刷新浏览器,就可以看到UI界面了。

    22、完成UI和合约的交互

        在上一步骤完成时,有个很漂亮的UI,但是还没有交互效果,因为并没有调用到智能合约。这
    部分逻辑在./src/app.js中完成,如下:
    
    App = {
      web3Provider: null,
      contracts: {},
    
      init: function() {
        // Load pets.
        $.getJSON('../pets.json', function(data) {
          var petsRow = $('#petsRow');
          var petTemplate = $('#petTemplate');
    
          //把一个个pet对象赋值到模板对应的标签上去
          for (i = 0; i < data.length; i ++) {
            petTemplate.find('.panel-title').text(data[i].name);
            petTemplate.find('img').attr('src', data[i].picture);
            petTemplate.find('.pet-breed').text(data[i].breed);
            petTemplate.find('.pet-age').text(data[i].age);
            petTemplate.find('.pet-location').text(data[i].location);
            petTemplate.find('.btn-adopt').attr('data-id', data[i].id);
    
            petsRow.append(petTemplate.html());
          }
        });
    
        return App.initWeb3();
      },
    
      initWeb3: function() {            //初始化web3
        //web3初始化过程参考:https://github.com/ethereum/web3.js
           //在初始化web3时,要先判断当前环境中是否已经有web3,没有再构建web3。因为在使用metamask时,会自带web3.
        if (typeof web3 !== 'undefined') {
          App.web3Provider = web3.currentProvider;
        } else {
          App.web3Provider = new Web3.prviders.HttpProvider("http://127.0.0.1:7545");   //ganache的地址
        }
        web3 = new Web3(App.web3Provider);
    
        return App.initContract();
      },
    
      initContract: function() {        //初始化合约
        $.getJSON('Adoption.json', function(data) {   //为何可直接加载Adoption.json文件呢,这是因为./build/contracts目录亿配置到服务器的环境中
          var AdoptionArtifact = data;
    
          App.contracts.Adoption = TruffleContract(AdoptionArtifact);
          App.contracts.Adoption.setProvider(App.web3Provider);
    
          return App.markAdopted();       //标记当前宠物是否被领养
        });
    
        return App.bindEvents();
      },
    
      bindEvents: function() {          //绑定事件
        $(document).on('click', '.btn-adopt', App.handleAdopt);     //btn-adopt是index.html,当这个按钮被点击时调用App的handleAdopt方法
      },
    
      markAdopted: function(adopters, account) {        //标记当前的宠物是否被领养
    
        var apotionInstance;
        //App.contracts.Adoption.deployed()可以拿到合约的实例,传递给then(function(instance)
        //中的instance。.then(function(instance)是promise的写法,
        App.contracts.Adoption.deployed().then(function(instance) {
          apotionInstance = instance;
          return apotionInstance.getAdopters.call();
        }).then(function(adopters) {            //上一步return apotionInstance.getAdopters.call()的返回值传递给了function(adopters)
    
          for(i =0; i< adopters.length; i++) {
            console.log(adopters[i]);
            //地址元素默认为0x0000000000000000000000000000000000000000
            if(adopters[i] !== '0x0000000000000000000000000000000000000000') {
              //button的文字写成Success,同时不能被点击
              $('.panel-pet').eq(i).find('button').text('Success').attr('disabled', true);
            }
          }
        }).catch(function(err) {          //捕获异常
          console.log(err.message);
        })
      },
    
      handleAdopt: function(event) {
        event.preventDefault();
        var apotionInstance;
        var petId = parseInt($(event.target).data('id'));
    
        web3.eth.getAccounts(function(error, accounts){       //拿到当前环境下的账号
          var account = accounts[0];      //取第一个账号
    
          App.contracts.Adoption.deployed().then(function(instance){
            apotionInstance = instance;
    
            return apotionInstance.adopt(petId, {from: account});
          }).then(function(result) {
            return App.markAdopted();       //标记状态
          } ).catch(function(err) {
            console.log(err.message);
          });
        });
      }
    };
    
    $(function() {
      $(window).load(function() {       //当window被加载时,会调用App.init
        App.init();
      });
    });
    

    22、运行(调试1)

    点了adopt没有反应,打开F12调试。(360浏览器)


    22、运行(调试2)。(谷歌浏览器)


    原因是要在谷歌浏览器的metamask中设置本地以太坊网络。

    23、metamask设置ganache网络

    我们的ganache中的地址默认为127.0.0.1:7545,如果metamask中有这个地址的网络则直接选择就好,如果没有则需要选择Custom RPC进行配置。



    这样还是不能领养宠物,因为网络中的地址和ganache中的10个地址不一样,要将ganache中的10个地址,导入到metamask网络中去

    24、将ganache中的一个地址私钥导入到metamask网络

    1)复制ganache中的第一个地址的私钥


    2)打开metemask对应网络,选择Import Account:
    3)输入刚才拷贝的私钥,导入即可看到我们选择的那个地址

    25、测试,这时完全可以正常使用了

    相关文章

      网友评论

          本文标题:truffle创建DAPP项目

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