Dapp开发

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

2018-03-26  本文已影响1966人  Abububiu

准备工作

  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

写在后面

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

参考资料

上一篇下一篇

猜你喜欢

热点阅读