• DApp demo之pet-shop


    注意: 这里使用的truffle版本为4.1.4,貌似使用高版本在truffle test时候会出问题,提示

    truffle/Assert.sol is not found等错误

    使用Truffle Box创建Truffle项目

    $ mkdir petshop
    $ cd petshop
    $ truffle unbox pet-shop
    

    项目目录结构

    $ ls
    box-img-lg.png  contracts/   node_modules/      src/
    box-img-sm.png  LICENSE      package.json       test/
    bs-config.json  migrations/  package-lock.json  truffle.js
    

    项目

    $ touch contracts/Adoption.sol
    

    内容如下:

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

    Migrations.sol代码如下:

    pragma solidity ^0.4.17;
    
    contract Migrations {
      address public owner;
      uint public last_completed_migration;
    
      modifier restricted() {
        if (msg.sender == owner) _;
      }
    
      function Migrations() public {
        owner = msg.sender;
      }
    
      function setCompleted(uint completed) public restricted {
        last_completed_migration = completed;
      }
    
      function upgrade(address new_address) public restricted {
        Migrations upgraded = Migrations(new_address);
        upgraded.setCompleted(last_completed_migration);
      }
    }
    

    编译

    solidity代码编译成以太坊虚拟机(Ethereum Virtual Machine,简称EVM)可以执行的字节码。

    $ truffle compile
    Compiling .contractsAdoption.sol...
    Compiling .contractsMigrations.sol...
    Writing artifacts to .uildcontracts
    

    运行ganache

    Quickly fire up a personal Ethereum blockchain which you can use to run tests, execute commands, and inspect state while controlling how the chain operates.

    Migration(迁移)

    A migration is a deployment script meant to alter the state of your application's contracts, moving it from one state to the next.

    $ touch migrations/2_deploy_contracts.js
    

    内容如下:

    var Adoption = artifacts.require("./Adoption.sol");
    
    module.exports = function (deployer) {
        deployer.deploy(Adoption);
    }
    
    $ truffle migrate
    Using network 'development'.
    
    Running migration: 1_initial_migration.js
      Deploying Migrations...
      ... 0x69df0a2b452808f94386709c3c22f6c10607ff7473d92558eb75c743cbae0e1c
      Migrations: 0x658dfbe4e9a30de42b8c48373eca4d05d6a0fe52
    Saving successful migration to network...
      ... 0xa7fd9f435d8d942bd3e83ab8fef01ed8f7d1d161803364a9193a526e681cb7c4
    Saving artifacts...
    Running migration: 2_deploy_contracts.js
      Deploying Adoption...
      ... 0x340f8e750a19a0178f54b328e59802231dd001c11ddb999776f900113e570dba
      Adoption: 0xa739c709b5c06110fb15433f9f65832f5188fe43
    Saving successful migration to network...
      ... 0x6c9b3b180ea294d968d7e607bd78c53872e08a688b01aca629e5bb6e73440c8e
    Saving artifacts...
    

    编写测试代码

    $ touch 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, "Adoption of pet ID 8 should be recorded.");
        }
    
        function testGetAdopterAddressByPetId() public {
            // Expected owner is this contract
            address expected = this;
    
            address adopter = adoption.adopters(8);
    
            Assert.equal(adopter, expected, "Owner of pet Id 8 should be recored.");
        }
    
        // Testing retrieval of all pet owners
        function testGetAdopterAddressByPetIdInArray() public {
            // Expected owner is this contract
            address expected = this;
    
            // store adopters in memory rather than contract's storage
            address[16] memory adopters = adoption.getAdopters();
    
            Assert.equal(adopters[8], expected, "Owner of pet ID 8 should be recorded.");
        }
    }
    

    测试

    $ truffle test
    

    效果:

     TestAdoption
        √ testUserCanAdoptPet (83ms)
        √ testGetAdopterAddressByPetId (87ms)
        √ testGetAdopterAddressByPetIdInArray (107ms)
    
    
      3 passing (1s)
    

    虽然vscode依然有错误提示,但是能够测试通过

    创建和智能合约交互的用户接口

    1) 实例化web3对象

    打开项目目录src/js/app.js
    修改initWeb3,使用下面内容替换带多行注释:

    // Is there an injected web3 instance?
    if (typeof web3 !== 'undefined') {
      App.web3Provider = web3.currentProvider;
    } else {
      // If no injected web3 instance is detected, fall back to Ganache
      App.web3Provider = new Web3.providers.HttpProvider('http://localhost:7545');
    }
    web3 = new Web3(App.web3Provider);
    

    2) 实例化合约

    修改initContract,使用下面内容替换带多行注释:

    $.getJSON('Adoption.json', function(data) {
      // Get the necessary contract artifact file and instantiate it with truffle-contract
      var AdoptionArtifact = data;
      App.contracts.Adoption = TruffleContract(AdoptionArtifact);
    
      // Set the provider for our contract
      App.contracts.Adoption.setProvider(App.web3Provider);
    
      // Use our contract to retrieve and mark the adopted pets
      return App.markAdopted();
    });
    

    3) 获取已收养的宠物并更新UI

    修改markAdopted,使用下面内容替换带多行注释:

    var adoptionInstance;
    
    App.contracts.Adoption.deployed().then(function(instance) {
      adoptionInstance = instance;
    
      return adoptionInstance.getAdopters.call();
    }).then(function(adopters) {
      for (i = 0; i < adopters.length; i++) {
        if (adopters[i] !== '0x0000000000000000000000000000000000000000') {
          $('.panel-pet').eq(i).find('button').text('Success').attr('disabled', true);
        }
      }
    }).catch(function(err) {
      console.log(err.message);
    });
    

    4) 处理adopt()函数

    修改handleAdopt,使用下面内容替换带多行注释:

    var adoptionInstance;
    
    web3.eth.getAccounts(function(error, accounts) {
      if (error) {
        console.log(error);
      }
    
      var account = accounts[0];
    
      App.contracts.Adoption.deployed().then(function(instance) {
        adoptionInstance = instance;
    
        // Execute adopt as a transaction by sending account
        return adoptionInstance.adopt(petId, {from: account});
      }).then(function(result) {
        return App.markAdopted();
      }).catch(function(err) {
        console.log(err.message);
      });
    });
    

    5) 安装配置metamask插件,创建并切换网络为localhost:7545

    6) 启动服务

    $ npm run dev
    
    

    app.js代码如下:

    App = {
      web3Provider: null,
      contracts: {},
    
      init: function () {
        // Load pets.
        $.getJSON('../pets.json', function (data) {
          var petsRow = $('#petsRow');
          var petTemplate = $('#petTemplate');
    
          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 () {
        // Is there an injected web3 instance?
        if (typeof web3 !== 'undefined') {
          App.web3Provider = web3.currentProvider;
        } else {
          // If no injected web3 instance is detected, fall back to Ganache
          App.web3Provider = new Web3.providers.HttpProvider('http://localhost:7545');
        }
        web3 = new Web3(App.web3Provider);
    
        return App.initContract();
      },
    
      initContract: function () {
        $.getJSON('Adoption.json', function (data) {
          // Get the necessary contract artifact file and instantiate it with truffle-contract
          var AdoptionArtifact = data;
          App.contracts.Adoption = TruffleContract(AdoptionArtifact);
    
          // Set the provider for our contract
          App.contracts.Adoption.setProvider(App.web3Provider);
    
          // Use our contract to retrieve and mark the adopted pets
          return App.markAdopted();
        });
        return App.bindEvents();
      },
    
      bindEvents: function () {
        $(document).on('click', '.btn-adopt', App.handleAdopt);
      },
    
      markAdopted: function (adopters, account) {
        var adoptionInstance;
    
        App.contracts.Adoption.deployed().then(function (instance) {
          adoptionInstance = instance;
    
          return adoptionInstance.getAdopters.call();
        }).then(function (adopters) {
          for (i = 0; i < adopters.length; i++) {
            if (adopters[i] !== '0x0000000000000000000000000000000000000000') {
              $('.panel-pet').eq(i).find('button').text('Success').attr('disabled', true);
            }
          }
        }).catch(function (err) {
          console.log(err.message);
        });
      },
    
      handleAdopt: function (event) {
        event.preventDefault();
    
        var petId = parseInt($(event.target).data('id'));
        var adoptionInstance;
    
        web3.eth.getAccounts(function (error, accounts) {
          if (error) {
            console.log(error);
          }
    
          var account = accounts[0];
    
          App.contracts.Adoption.deployed().then(function (instance) {
            adoptionInstance = instance;
    
            // Execute adopt as a transaction by sending account
            return adoptionInstance.adopt(petId, { from: account });
          }).then(function (result) {
            return App.markAdopted();
          }).catch(function (err) {
            console.log(err.message);
          });
        });
      }
    
    };
    
    $(function () {
      $(window).load(function () {
        App.init();
      });
    });
    

    效果:

    出现的问题

    1 > 执行truffle test的时候出现如下错误: truffle/Assert.sol is not found

    $ npm view truffle versions
    $ npm uninstall -g truffle
    $ npm install -g truffle@4.1.4
    

    删除build目录
    然后重新执行命令即可。

    $ truffle compile
    $ truffle test
    

    参考:

  • 相关阅读:
    Python正课48 —— 匿名函数及其应用
    Python正课47 —— 面向过程编程思想
    Python正课46 —— 二分法
    Python正课45 —— 函数的递归调用
    Python正课44 —— 生成式
    Python正课43 —— 三元表达式
    SQL数据库操作命令大全
    css 高度写死 下滚动时ios 滚动不协调处理
    记录:js删除数组中某一项或几项的几种方法
    本次存储存数组对象
  • 原文地址:https://www.cnblogs.com/hupeng1234/p/9856849.html
Copyright © 2020-2023  润新知