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

准备工作

  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

写在后面

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

参考资料

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,457评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,837评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,696评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,183评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,057评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,105评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,520评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,211评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,482评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,574评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,353评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,897评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,489评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,683评论 2 335

推荐阅读更多精彩内容