如何编写智能合约(Smart Contract)- 从零构建和部署去中心化投票App

区块链技术巴比特2017-12-01 15:51:42  阅读 -评论 1  阅读原文

课程目标 了解区块链智能合约 学会搭建智能合约开发环境 学会如何编译智能合约 学会如何将智能合约部署到区块链 学会如何通过WebApp和智能合约尽心互动 掌握DApp(去中心化App)的整个开发部署流程 掌握去中心化在实战产品中应用的重大意义 项目效果图

如何编写智能合约(Smart Contract)- 从零构建和部署去中心化投票App

编辑器选择

理论上讲任何编辑器都可以编写Solidity合约代码,比如:WebStorm,VSCode,Sublime,等等。我选择的是Atom,没有任何理由,因为Atom轻量并且界面漂亮。

移步https://atom.io/地址,下载安装Atom。 autocomplete-solidity代码自动补齐

如何编写智能合约(Smart Contract)- 从零构建和部署去中心化投票App

linter-solium、linter-solidity代码错误检查 language-ethereum支持Solidity代码高亮以及Solidity代码片段

如何编写智能合约(Smart Contract)- 从零构建和部署去中心化投票App

安装所需工具

首先开发机上必须装好Node.js,再使用以下命令安装所需的工具:

$ npm install -g ethereumjs-testrpc truffle

liyuechun:~ yuechunli$ npm install -g ethereumjs-testrpc truffle /usr/local/bin/testrpc -> /usr/local/lib/node_modules/ethereumjs-testrpc/build/cli.node.js /usr/local/bin/truffle -> /usr/local/lib/node_modules/truffle/build/cli.bundled.js + truffle@3.4.9 + ethereumjs-testrpc@4.1.3 added 1 package and updated 7 packages in 76.132s liyuechun:~ yuechunli$ 创建项目

/Users/liyuechun/Desktop/1012/Voting liyuechun:Voting yuechunli$ ls liyuechun:Voting yuechunli$ pwd /Users/liyuechun/Desktop/1012/Voting liyuechun:Voting yuechunli$ truffle unbox react-box Downloading... Unpacking... Setting up... Unbox successful. Sweet! Commands: Compile: truffle compile Migrate: truffle migrate Test contracts: truffle test Test dapp: npm test Run dev server: npm run start Build for production: npm run build liyuechun:Voting yuechunli$ 项目结构

如何编写智能合约(Smart Contract)- 从零构建和部署去中心化投票App

contracts:编写智能合约的文件夹,所有的智能合约文件都放置在这里 migrations:部署合约配置的文件夹 src:基于React的Web端源码 test:智能合约测试用例文件夹 编写投票Dapp智能合约

在contracts文件夹下创建Voting.sol文件,将下面的代码拷贝到文件中。

pragma solidity ^0.4.4; contract Voting { // liyuechun -> 10 // xietingfeng -> 5 // liudehua -> 20 mapping (bytes32 => uint8) public votesReceived; // 存储候选人名字的数组 bytes32[] public candidateList; // 构造函数 初始化候选人名单 function Voting(bytes32[] candidateNames) { candidateList = candidateNames; } // 查询某个候选人的总票数 function totalVotesFor(bytes32 candidate) constant returns (uint8) { require(validCandidate(candidate) == true); // 或者 // assert(validCandidate(candidate) == true); return votesReceived[candidate]; } // 为某个候选人投票 function voteForCandidate(bytes32 candidate) { assert(validCandidate(candidate) == true); votesReceived[candidate] += 1; } // 检索投票的姓名是不是候选人的名字 function validCandidate(bytes32 candidate) constant returns (bool) { for(uint i = 0; i < candidateList.length; i++) { if (candidateList[i] == candidate) { return true; } } return false; } } 通过remix + metamask部署合约到Kovan Test Net 在Google浏览器里面安装MetaMask插件

如何编写智能合约(Smart Contract)- 从零构建和部署去中心化投票App

打开https://remix.ethereum.org将合约代码拷贝到里面

如何编写智能合约(Smart Contract)- 从零构建和部署去中心化投票App

确保MetaMask账号处于等于状态,并且有一定的以太币支付给矿工。 确保Environment是Injected Web3,如果切换不过来,关掉浏览器重新启动 在create函数中输入一个数组,数组里面的内容为候选人名单 点击create按钮,会弹出MetaMask界面让你确认,确认提交,过一会儿,合约就部署成功 可以测试给某个候选人投票,查询某个候选人的票数 拷贝合约地址

如何编写智能合约(Smart Contract)- 从零构建和部署去中心化投票App

0xd3f33a2e553b363b432d7f81f721a2a6202ecc67 编译合约

liyuechun:Voting yuechunli$ truffle compile Compiling ./contracts/Migrations.sol... Compiling ./contracts/SimpleStorage.sol... Compiling ./contracts/Voting.sol... Writing artifacts to ./build/contracts liyuechun:Voting yuechunli$

编译完合约以后在build/contracts文件夹下面会有一个Voting.json的abi文件。

查看Voting.json文件内容

{ "contract_name": "Voting", "abi": [ { "constant": true, "inputs": [ { "name": "candidate", "type": "bytes32" } ], "name": "totalVotesFor", "outputs": [ { "name": "", "type": "uint8" } ], "payable": false, "type": "function" }, { "constant": true, "inputs": [ { "name": "candidate", "type": "bytes32" } ], "name": "validCandidate", "outputs": [ { "name": "", "type": "bool" } ], "payable": false, "type": "function" }, { "constant": true, "inputs": [ { "name": "", "type": "bytes32" } ], "name": "votesReceived", "outputs": [ { "name": "", "type": "uint8" } ], "payable": false, "type": "function" }, { "constant": true, "inputs": [ { "name": "", "type": "uint256" } ], "name": "candidateList", "outputs": [ { "name": "", "type": "bytes32" } ], "payable": false, "type": "function" }, { "constant": false, "inputs": [ { "name": "candidate", "type": "bytes32" } ], "name": "voteForCandidate", "outputs": [], "payable": false, "type": "function" }, { "inputs": [ { "name": "candidateNames", "type": "bytes32[]" } ], "payable": false, "type": "constructor" } ], "unlinked_binary": "0x6060604052341561000f57600080fd5b6040516103113803806103118339810160405280805190910190505b600181805161003e929160200190610046565b505b506100b5565b828054828255906000526020600020908101928215610083579160200282015b828111156100835782518255602090920191600190910190610066565b5b50610090929150610094565b5090565b6100b291905b80821115610090576000815560010161009a565b5090565b90565b61024d806100c46000396000f300606060405263ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416632f265cf78114610069578063392e6678146100955780637021939f146100bf578063b13c744b146100eb578063cc9ab26714610113575b600080fd5b341561007457600080fd5b61007f60043561012b565b60405160ff909116815260200160405180910390f35b34156100a057600080fd5b6100ab60043561015d565b604051901515815260200160405180910390f35b34156100ca57600080fd5b61007f6004356101af565b60405160ff909116815260200160405180910390f35b34156100f657600080fd5b6101016004356101c4565b60405190815260200160405180910390f35b341561011e57600080fd5b6101296004356101e7565b005b60006101368261015d565b151560011461014457600080fd5b5060008181526020819052604090205460ff165b919050565b6000805b6001548110156101a457600180548491908390811061017c57fe5b906000526020600020900160005b5054141561019b57600191506101a9565b5b600101610161565b600091505b50919050565b60006020819052908152604090205460ff1681565b60018054829081106101d257fe5b906000526020600020900160005b5054905081565b6101f08161015d565b15156001146101fb57fe5b6000818152602081905260409020805460ff8082166001011660ff199091161790555b505600a165627a7a723058206783a7ff47eae16f18011a9db2a3cc983350b779bf3181b7623c18d4bce363180029", "networks": {}, "schema_version": "0.0.5", "updated_at": 1507806214330 }

这个文件是编译后的abi文件,待会儿需要将这个文件的json导入到App.json中。

查看src/utils/getWeb3.js文件内容

import Web3 from 'web3' let getWeb3 = new Promise(function(resolve, reject) { // Wait for loading completion to avoid race conditions with web3 injection timing. window.addEventListener('load', function() { var results var web3 = window.web3 // Checking if Web3 has been injected by the browser (Mist/MetaMask) if (typeof web3 !== 'undefined') { // Use Mist/MetaMask's provider. web3 = new Web3(web3.currentProvider) results = { web3: web3 } console.log('Injected web3 detected.'); resolve(results) } else { // Fallback to localhost if no web3 injection. var provider = new Web3.providers.HttpProvider('http://localhost:8545') web3 = new Web3(provider) results = { web3: web3 } console.log('No web3 instance injected, using Local web3.'); resolve(results) } }) }) export default getWeb3

这个文件主要是封装了一个getWeb3的promiss供我们直接使用,可以从getWeb3直接获取到web3对象供App.js文件中使用。

修改app.js前端代码和合约进行互动

import React, { Component } from 'react' import VotingContract from '../build/contracts/Voting.json' import getWeb3 from './utils/getWeb3' import './css/oswald.css' import './css/open-sans.css' import './css/pure-min.css' import './App.css' const contractAddress = "0xd3f33a2e553b363b432d7f81f721a2a6202ecc67"; var votingContractInstance; var _modifyVotingCount = (candidates,i,votingCount) => { console.log("---------"); console.log(candidates); console.log(i); console.log(votingCount); let obj = candidates[i]; obj.votingCount = votingCount; return candidates; } class App extends Component { constructor(props) { super(props) this.state = { candidates: [ { "name": "Rama", "id": 100, "votingCount": 0 }, { "name": "Nick", "id": 101, "votingCount": 0 }, { "name": "Jose", "id": 102, "votingCount": 0 }, { "name": "liyuechun", "id": 103, "votingCount": 0 } ], candidatesVoteCount: ["0","0","0","0"], web3: null } } componentWillMount() { // Get network provider and web3 instance. // See utils/getWeb3 for more info. getWeb3 .then(results => { this.setState({ web3: results.web3 }) // Instantiate contract once web3 provided. this.instantiateContract() }) .catch(() => { console.log('Error finding web3.') }) } instantiateContract() { /* * SMART CONTRACT EXAMPLE * * Normally these functions would be called in the context of a * state management library, but for convenience I've placed them here. */ const contract = require('truffle-contract') const votingContract = contract(VotingContract) votingContract.setProvider(this.state.web3.currentProvider) // Declaring this for later so we can chain functions on SimpleStorage. // Get accounts. this.state.web3.eth.getAccounts((error, accounts) => { votingContract.at(contractAddress).then((instance) => { votingContractInstance = instance; for (let i = 0; i < this.state.candidates.length; i++) { let object = this.state.candidates[i]; console.log(accounts[0]); console.log(votingContractInstance); console.log(votingContractInstance.totalVotesFor(object.name)); votingContractInstance.totalVotesFor(object.name).then(result => { console.log(i); console.log(result.c[0]); this.setState({ candidates: _modifyVotingCount(this.state.candidates,i,result.c[0]) }); }); } }) }) } render() { return (
    { this.state.candidates.map((object) => { console.log(object); return (
  • 候选人:{object.name} 支持票数:{object.votingCount}
  • ) }) }
{ console.log(this.refs.candidateInput); console.log(this.refs.candidateInput.value); let candidateName = this.refs.candidateInput.value; console.log(this.state.web3.eth.accounts[0]); votingContractInstance.voteForCandidate(candidateName).then((result => { console.log(result); console.log(candidateName); let number = 0; for(let i = 0; i < this.state.candidates.length; i++) { let object = this.state.candidates[i]; if (object.name === candidateName) { number = i; break; } } votingContractInstance.totalVotesFor(candidateName).then(result => { this.setState({ candidates: _modifyVotingCount(this.state.candidates,number,result.c[0]) }); }); })); }}>Voting ); } } export default App

如何编写智能合约(Smart Contract)- 从零构建和部署去中心化投票App

声明:链世界登载此文仅出于分享区块链知识,并不意味着赞同其观点或证实其描述。文章内容仅供参考,不构成投资建议。投资者据此操作,风险自担。此文如侵犯到您的合法权益,请联系我们100@7234.cn

参与讨论 (1 人参与讨论)

相关推荐

​公告丨欧盟首家合规交易所ZBX发布IOS平台应用

​公告丨欧盟首家合规交易所ZBX发布IOS平台应用

加密货币的应用前景与行业发展很大程度上取决于加密交易的合规化,因为合规化的加密交易可以保护用户与投资者的资金财产。ZBX.com作为一家欧盟合规交易所,其与众多欧洲重要银行合作,通过自身网络平台和刚刚发布的iOS应用程序为用户提供深层流动性。据悉,Android应用也将在未来几天内发布。ZBX交易所目前向平台新注册的用户提供50个价值共为5欧元的平台代币ZBX。 首席执行官Dave Pulis表示

Facebook跨境支付三道难题 高管看空纷纷离职

Facebook跨境支付三道难题 高管看空纷纷离职

全球最大社交媒体平台Facebook上周四(3.21)盘后意外宣布,创业"元老"之一、公司首席产品官Chris Cox,以及主管WhatsApp业务的副总裁Chris Daniels将辞职。Cox曾是Facebook首批15个工程师之一,被认为是CEO扎克伯格的接班人。克里斯考克斯(Chris Cox)、马克扎克伯格和内奥米格里特(备注)Cox在个人FB主页上撰写长文透露,自己离开的原因部分与公司

WhatsApp创始人阿克顿力促删掉Facebook  ——专家分析保护用户隐私须去中心化

WhatsApp创始人阿克顿力促删掉Facebook ——专家分析保护用户隐私须去中心化

是时候删掉Facebook。WhatsApp联合创始人布莱恩-阿克顿日前在其母校斯坦福大学发表演讲时呼吁大学生们删了Facebook,事实上这不是阿克顿第一次呼吁人们删除Facebook。与脸书高层在用户隐私处理上理念不一致,使得阿克顿放弃了价值8.5亿美元股权,辞职成为了怼Facebook阵营的中坚力量。Whatsapp已无隐私原本采用Signal的Open Whisper Systems加密通

​Facebook不敢干的区块链BCM已经干了

​Facebook不敢干的区块链BCM已经干了

Facebook并不敢上区块链。上周Facebook老板小扎的千字博文《Privacy-Focused Vision for Social Networking 》(以隐私为中心的社交网络愿景)压根没有提到区块链、发币和去中心化这些字眼。隐私加密通信这档事,在国内马桶MT、BCM通信都已推出了产品。不仅如此,Facebook迟迟不敢提的区块链和去中心化,BCM通信也已经给出了实现方案和惊人的系统设

俄罗斯区块链平台Waves发布智能合约游戏

Waves区块链平台本周面向中国市场正式发布一款智能合约互动游戏Dice Roller,作为Waves去中心化生态系统的补充。此次Waves发布的智能合约游戏名叫Dice Roller,是一款经典的骰子游戏。玩家只需要为浏览器安装"Waves钱包"和"Waves Keeper"即可参与游戏。玩家从骰子的6个数字中,最多选择5个数字用Waves波浪币投注。每次投注的数字越多,获胜的几率也就越高,但相

区块链投资趋势报告:巨头入场布局行业趋于成熟

区块链投资趋势报告:巨头入场布局行业趋于成熟

来自:https://mp.weixin.qq.com/s?__biz=MzI4NzIxOTY1NA==&amp;mid=2650632639&amp;idx=1&amp;sn=e6d1c29731d992a80410aaee82ec3ea6&amp;chksm=f3d8db16c4af520097e4a64a71b1d4743ac326b9f027

重新发明货币

重新发明货币

一、货币的演化过程 先简单回顾一下人类货币的演化过程,大概有以下阶段: a. 1.0版本:自然货币(贝壳、牲口、金银……) 这个阶段,货币基于一般等价物的稀有性或者实用性,货币不可能出现人为操纵的超发。 b. 2.0版本:早期纸币、银票到本位纸币 当贸易量越来越大,实物货币太不方便了,而且大家发现其实并不在意货币本身有什么价值,在意的只是这么多的货币能不能交换到足够的物品,于是纸币这种信用货

从比特币交易看欧洲央行虚拟货币分类

从比特币交易看欧洲央行虚拟货币分类

  互联网对传统社会的颠覆从未停止,在其完成对信息流、商流、物流、资金流的初步改造之后,或将以虚拟货币的形式打破现有货币体系   4月18日,在中国极客张沈鹏创办的比特币交易平台(42BTC.com)上,比特币对人民币的平均交易价为576元。当天,该平台完成了100个比特币的交易量。仅仅过去一周,4月25日上午,比特币对人民币的平均交易价已达到906元。据42BTC网站统计:在过去的32个月

麦妖榜
更新日期 2019-06-18
排名用户贡献值
1BitettFan23992
2等待的宿命23809
3六叶树20309
4区块大康18727
5牛市来了16520
6天下无双16192
7linjm122716021
8lizhen00215101
9让时间淡忘14475
10冷风大q11188
返回顶部 ↑