以太坊应用实战3-基于NodeJS开发编译部署DAPP

在初步了解了以太坊基本概念之后,我们可以着手开始进行开发,此次我们将通过web3.js封装的以太坊接口来与区块链进行交互。应用整体结构如图所示:


3.1 以太坊应用结构

获得一个全节点相当耗时,本次实战将使用ganache软件模拟区块链节点,以便快速开发并测试应用。

为了便于开发和测试,ganache默认会自动创建10个账户,每个账户有100个以太币。


3.2 模拟区块链节点

上图所示,模拟节点的监听地址和端口为127.0.0.1:7545, 在使用web3.js时,我们将传入此地址告诉web3.js应当连接哪一个节点,接下来我们将使用第一个账号(0x627306090abaB3A6e1400e9345bC60c78a8BEf57)创建交易、发送/接受以太币。

投票合约设计

我们使用Solidity语言来编写合约,合约的属性用来保存合约的状态,合约中的方法为调用提供接口


3.3 Voting Class

投票合约包含以下内容:

* 构造函数Voting,用来初始化候选人名单

* 投票方法vote, 为指定的候选人投票数加1

*查询方法totalVotesFor(),查询指定候选人的得票数

有几点是区别以往

1. 合约的状态是持久化到区块链上,对合约状态的修改需要消耗费用

2. 只有部署合约到区块链上时,才会调用构造函数

3. 合约不可更改,如果想更新合约需要再次部署,但旧的合约仍会在区块链上,合约的状态也依然存在。

投票合约开发

合约代码保存在 voting.sol文件中

编译器要求

pragma solidity ^0.4.18

合约声明

contract Voting{}

contract 关键字用来声明一个合约

字典类型:mapping

mapping(bytes32 => uint8) public votesReceived;

votesReceived是一个键值对,其Key为候选者名字,类型为byte32字符串,值为每个候选者的得票数,类型为uint8

投票方法vote为指定的候选人投票。

function vote(byte32 candidate) public {

    require(validCandidate(candidate));

    votesReceived[candidate] += 1;

}

require 类似断言,只有条件为真时,合约才会继续执行。

validCandidate()方法判断指定的候选人是否是有效的候选人

function validCandidate(byte32 candidate) view public returns (bool) {

    for(uint i = 0; i< candidateList.length; i++) {

        if(candidateList[i] == candidate) {

            return true;

        }

    }

}

完整代码如下:

pragma solidity ^0.4.18;

contract Voting {

      mapping (bytes32 => uint8) public votesReceived;

      bytes32[] public candidateList;

      function Voting(bytes32[] candidateNames) public {

            candidateList = candidateNames;  }

      function totalVotesFor(bytes32 candidate) view public returns (uint8) {

        require(validCandidate(candidate));

            return votesReceived[candidate];

      }

      function vote(bytes32 candidate) public {

            require(validCandidate(candidate));

            votesReceived[candidate]  += 1;

      }

      function validCandidate(bytes32 candidate) view public returns (bool) {

            for(uint i = 0; i < candidateList.length; i++) {

                  if (candidateList[i] == candidate) {

                        return true;

                  }

        }

            return false;

      }

}

投票合约编译

启动node控制台,初始化web3对象,并向模拟的区块链节点(http://127.0.0.1:7545)查询所有账户

> Web3 = require('web3')

> web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));

> web3.eth.accounts

[ '0x627306090abab3a6e1400e9345bc60c78a8bef57',  '0xf17f52151ebef6c7334fad080c5704d77216b732',  '0xc5fdf4076b8f3a5357c5e395ab970b5b54098fef',  '0x821aea9a577a9b44299b9c15c88cf3087f3b5544',  '0x0d1d4e623d10f9fba5db95830f7d3839406c6af2',  '0x2932b7a2355d6fecc4b5c0b6bd44cc31df247a2e',  '0x2191ef87e392377ec08e7c08eb105ef5448eced5',  '0x0f4f2ac550a1b4e2280d04c21cea7ebd822934b5',  '0x6330a553fc93768f612722bb8c2ec78ac90b3bbc',  '0x5aeda56215b167893e80b4fe645ba6d5bab767de' ]

编译合约,首先载入voting.sol的内容,之后使用solc编译器对合约代码进行编译

code = fs.readFileSync('voting.sol')

solc = require('solc')

compiledCode = solc.compile(code)


其编译后的代码有两个重要字段

bytecode: 投票合约编译后的字节码,将要被部署到区块链上

interface: 投票合约接口

投票合约部署

在node控制台下执行以下命令

abi = JSON.parse(compiledCode.contracts[':Voting'].interface)

contract = web3.eth.contract(abi)

byteCode = compiledCode.contracts[':Voting'].bytecode

deployedContract = contract.new(['zhangsan','lisi','wama'],{ data: byteCode,from:web3.eth.accounts[0], gas:4700000})

> deployedContract.address

'0x8cdaf0cd259887258bc13a92c0a6da92698644c0'

contractInstance = contract.at(deployedContract.address)

contract对象的new()方法将投票合约部署到区块链上,至此我们已经成功部署了投票合约,并且获得一个实例contractInstance,现在可以通过该实例与合约进行交互

合约交互

通过totalVotesFor方法查看候选人的票数

contractInstance.totalVotesFor.call('zhangsan')

{ [String: '0'] s: 1, e: 0, c: [ 0 ] }

vote()投票给候选人,下面的代码给zhangsan 投了二次票

> contractInstance.vote('zhangsan',{from:web3.eth.accounts[0]})

'0x7fd48761ba8f1fb83239ad6c5da1eff16cbec5259f6c60d28c5464523ac17f6f'

>contractInstance.vote('zhangsan',{from:web3.eth.accounts[0]})

'0xcd479e1b7d492dc608d584178adce1181e0d251974f70a1cac3f36c00a9eb27b'

再次通过totalVotesFor查看zhangsan的得票数

> contractInstance.totalVotesFor.call('zhangsan').toString()

'2'

每进行一次投票就产生一次交易,voteForCandidate()将返回交易的凭证,任何时候都可以通过交易凭证查看交易


3.4 transactions

总结

当前为止我们已经接触到的相关知识点

1. nodejs 和 ganache 作为开发环境开发编译部署合约

2. 开发了简单的投票合约,并编译部署到了区块链节点

3. 使用nodejs控制台与合约进行交互

4. 所有数据保存到了区块链,不可修改

5. 可独立验证每个候选人获得了多少投票

后续将使用Truffle框架构建此投票应用。

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

推荐阅读更多精彩内容