美文网首页Dapp开发
以太坊DApp开发入门教程(一) 环境配置及truffle入门

以太坊DApp开发入门教程(一) 环境配置及truffle入门

作者: Abububiu | 来源:发表于2018-03-26 15:29 被阅读1966次

    准备工作

    1. 安装Nodejs环境,选择对应的平台,并下载LTS版本。安装完成后,在终端输入下面命令查看,如果正常输出版本号,则安装成功
    node -v
    
    image.png
    1. 安装truffle框架,输入如下命令安装
    sudo npm install -g truffle
    
    1. 安装Ganache,下载对应平台安装包安装即可。Ganache是一个图形化的以太坊私有链程序,打开后便在本地建立起一个以太坊私有链,方便快捷。启动Ganache后,会有10个默认账户,并都有100Eth,当然,这只是测试用的,因为在你的私有链上。安装完成后请开启Ganache,后面部署合约时会用到
      image.png
    2. 下载metamask以太坊钱包。介于网络的原因,我们用firfox或者Opera版本的插件。当然,你也可以直接下载浏览器。

    创建目录,编程初体验

    1. 首先,我们创建一个目录。这就不需要多说了,我的目录就叫SmartContart


      image.png
    2. 在当前文件夹下输入truffle命令,来unbox一个项目
    truffle unbox pet-shop
    
    image.png
    1. 用你的编辑器打开这个项目,我使用的是Atom,文件夹介绍在图里。有一点需要说明下,migrations是部署合约的文件夹,通过js来部署(图中migrations的解释写错了,请忽略)。


      image.png
    2. 我们新建一个智能合约,叫Election.sol,并写上下面的代码:
    pragma solidity ^0.4.2; //这句声明了我们的solidity版本
    
    //声明一个合约 contract是关键字,Election是合约名字,合约名字和文件名要一致
    contract Election {
        /* 声明一个public 的string类型的状态变量(可以理解为成员变量) */
        string public candidate;
    
        /* constractor 函数名和合约名一样的函数就是构造函数,与C++相似*/
        /* 构造函数是public的,因为需要外部来调用 */
        function Election() public{
            candidate = "Candidate 1";
        }
    }
    

    这个代码声明了一个合约,然后在构造函数中给candicate这个状态变量赋值,仅此而已。

    1. 在终端中打开项目目录,输入下面的命令部署合约
    truffle migrate
    
    image.png
    1. 部署后,输入truffle console,打开truffle终端,输入下面这行代码
    Election.deployed().then(function(instance) { app = instance})
    

    你会得到undefined错误,原因我们暂时先放放
    然后输入app.address,你会看到一个地址被打印出来,这就是合约地址,再输入app.candicate(),你会看到打印出来的值是我们在构造函数中赋值给candicate状态变量的值

    image.png
    当我们声明candicate状态变量为public时,会自动生成同名的get函数来获取这个状态变量的值,我们通过创建的app对象访问candicate,便得到了candicate的值。此时,打开你的Ganache,你会发现有个账户的以太币减少了,这就是部署合约的开销。
    image.png
    1. 到此,我们已经部署了一个很单纯的合约,只有读取变量的功能。接下来我们给Election.sol文件稍微增加些代码。我们把Candidate换成了一个结构体,添加了一个mapping及addCandidate方法。我们希望通过Candidate来保存某个Candidate的票数,通过addCandidate来创建候选人
    pragma solidity ^0.4.2; //这句声明了我们的solidity版本
    
    //声明一个合约 contract是关键字,Election是合约名字,合约名字和文件名要一致
    contract Election {
        /* 声明一个candicate结构 */
        struct Candidate{
            uint id;
            string name;
            uint voteCount;
        }
        /* 匹配到一个Candicate结构,通过一个mapping来做
        mapping是key-value的,uint类型作为key,可以对应Candicate
        结构里的id,而value则是一个Candicate对象
        mapping操作会改变合约状态,将candicates放在区块链上存储*/
        mapping (uint => Candidate) public candidates;
    
        /* 我们需要手动记录mapping的大小,因为mapping不能被遍历
        mapping的key对应的value如果不存在,则返回value类型的默认值
        比如unit类型返回的是0,Candidate类型就返回空Candidate对象 */
        uint public candidatesCount;
    
        /* constractor 函数名和合约名一样的函数就是构造函数,与C++相似*/
        /* 构造函数是public的,因为需要外部来调用 */
        function Election() public{
            addCandidate("candidate 1");
            addCandidate("candidate 2");
        }
    
        /* 变量前加下划线表明这个变量是局部变量,不是状态变量 */
        function addCandidate(string _name) private {
            candidatesCount ++;
            candidates[candidatesCount] = Candidate(candidatesCount, _name, 0);
        }
    }
    

    修改完代码后,在终端中输入truffle migrate --reset重新部署合约。加入--reset是因为之前的合约已经记录在区块链上了,无法修改,只能重新部署一套合约,重新部署的合约会生成新的合约地址
    部署成功后,进入truffle终端,输入下面的代码创建对象

    Election.deployed().then(function(instance) { app = instance})
    

    然后输入下面的代码,创建candidate

    app.candidates(1).then(function(c) { candidate = c;})
    
    image.png
    上图中访问candidate的成员id不能像C++等语言一样,通过.操作符来访问结构体中的成员,EVM不认识结构体,结构体只是Solidity里的一个语法糖,方便大家写而已。我们需要通过下标来访问candidate里的成员。打印出来的id显示为一个BigNumber,这是JavaScript的表示方法,c对应的是值,也就是id为1,正如我们创建的那样。

    如果需要显示正常些,可以用toNumber()方法和toString()方法来得到正常些的结果

    image.png

    调用以太坊的接口

    上面的程序已经可以记录候选人的票数,但是投票人怎么投票呢?在解决这个问题之前,我们先看看如何远程调用以太坊提供的方法(functions)

    以太坊提供了一个web3.js库来访问以太坊内部的方法或者命令。
    我们可以在truffle终端中调用下web3的方法,在truffle终端中输入web3.eth,你会得到一堆输出

    image.png
    这就是web3中eth提供的函数,我们试试accounts,它会列出Ganache网络内的账户地址。这个命令与在自己搭建的私有链中查看accounts的调用方式不同之处在于前面加了个web3
    image.png

    合约测试

    因为智能合约一旦部署,不可更改,合约的Bug也会随之在区块链上永垂不朽。如果要修复Bug,必须重新部署合约,这会极大影响用户体验,所以奋不顾身地测试合约也是必要的。测试文件可以是Solidity编写,也可以是JavaScript来写。我们先看看JavaScript如何写测试。

    1. 准备工作
      我们需要用到mocha测试框架和chai断言库,通过下面的命令就能安装他们
    sudo npm install --global mocha
    sudo npm install chai
    
    1. 写测试脚本
      在test文件夹中创建一个election.js的测试脚本
      image.png
      测试脚本的代码如下,更多关于mocha测试框架和chai断言库的教程可以去网上搜搜
    var Election = artifacts.require("./Election.sol");
    
    // 声明合约 第一个参数是段描述,描述你的测试,第二个参数是个函数
    //函数中的it 是一个测试用例,一个contract可以包含多个it
    contract("Election", function(accounts){
        it("init with two candidates", function(accounts){
            return Election.deployed().then(function (instance){
                return instance.candidatesCount();
            }).then(function(count){
               assert.equal(count, 2);
            });
        });
    });
    

    写好之后在终端中打开项目目录,输入truffle test,如果看到下面的输出,则测试通过

    image.png

    写在后面

    第一篇教程就暂时写到这里,希望对大家有所帮助,后续教程即将来袭

    参考资料

    相关文章

      网友评论

      • 何呵呵_f907:你好 请问我使用truffle migrate命令之后为什么报错Warning: Defining constructors as functions with the same name as the contract is deprecated. Use "constructor(...) { ... }" instead.
        function Election() public{
        ^ (Relevant source part starts here and spans across multiple lines). 在实时编译网站就不会报错
        Abububiu:@何呵呵_f907 这个是编译的警告,和编译器版本有关系,构造函数声明的方式有所改变,提示你使用新的构造函数定义方式。你也可以选择忽略掉。

      本文标题:以太坊DApp开发入门教程(一) 环境配置及truffle入门

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