主页 > imtoken钱包苹果版价值 > 以太坊开发去中心化投票 DApp 和智能合约
以太坊开发去中心化投票 DApp 和智能合约
环境准备
Ubuntu 16.04,64 位
还需要安装以太坊相关环境:
可以参考我之前的一篇文章:
另外本文也会用到webpack,网上有很多安装教程。 如果您对这部分内容不熟悉,请自行查阅和研究。 需要注意的是,本文我使用的webpack版本是3.x,写这篇文章的时候webpack4.x已经发布了。 4.x的变化比较大。 建议您使用 3.x 版本运行本文中的代码示例。
编写智能合约
首先在用户目录下创建会议目录,进入该目录执行truffle init,该命令会创建如下子目录和文件:
修改truffle.js文件如下:
module.exports = {
networks: {
development: {
host: "localhost",
port: 8545,
network_id: "*" // 匹配任何network id
}
}
};
这里是我们设置后面部署智能合约的位置,否则会报网络错误。
打开终端并输入 testrpc 以运行测试节点。 testrpc是内存中完整的区块链测试环境。 启动testrpc后以太坊web开发,默认会创建10个账号。 Available Accounts 为账户列表,Private Keys 为对应的账户密钥。
进入contracts目录,这里是存放合约代码的地方。 我们可以使用sublime等工具编写测试合约代码。 我这里只贴出部分代码,完整源码地址会在文末给出。
pragma solidity ^0.4.19;
contract Conference { // can be killed, so the owner gets sent the money in the end
address public organizer;
mapping (address => uint) public registrantsPaid;
uint public numRegistrants;
uint public quota;
event Deposit(address _from, uint _amount); // so you can log the event
event Refund(address _to, uint _amount); // so you can log the event
function Conference() {
organizer = msg.sender;
quota = 100;
numRegistrants = 0;
}
...
契约的内容很简单。 它是会议的智能合约,与会者可以通过它购买门票,主办方可以设置与会人数上限和退款政策。
编译和部署智能合约
修改migrations下的1_initial_migration.js文件如下:
//var Migrations = artifacts.require("./Migrations.sol");
var Conference = artifacts.require("./Conference.sol");
module.exports = function(deployer) {
//deployer.deploy(Migrations);
deployer.deploy(Conference);
};
编译,
$ sudo truffle compile --compile-all
注意看是否有错误。
默认情况下,Truffle 只编译自上次编译以来修改过的文件,以减少不必要的编译。 如果要编译所有文件,可以使用 --compile-all 选项。
然后会多出一个build目录,这个目录下的文件不要做任何修改。
部署,
$ sudo truffle migrate --reset
此命令将执行 migrations 目录中的所有 js 文件。 如果之前执行过truffle migrate命令,再次执行的话,只会部署新的js文件。 如果没有新的js文件,则不会有任何效果。 如果使用--reset参数,所有脚本的部署都会重新执行。
测试下,在test目录下添加一个conference.js测试文件,
var Conference = artifacts.require("./Conference.sol");
contract('Conference', function(accounts) {
console.log("start testing");
//console.log(accounts);
var owner_account = accounts[0];
var sender_account = accounts[1];
it("Initial conference settings should match", function(done) {
Conference.new({from: owner_account}).then(
function(conference) {
conference.quota.call().then(
function(quota) {
assert.equal(quota, 100, "Quota doesn't match!");
}).then(
function() {
return conference.numRegistrants.call();
}).then(
function(num) {
assert.equal(num, 0, "Registrants doesn't match!");
return conference.organizer.call();
}).then(
function(organizer) {
assert.equal(organizer, owner_account, "Owner doesn't match!");
done();
}).catch(done);
}).catch(done);
});
...
这里只贴出部分代码,四个测试用例,运行truffle test查看测试结果。
$ truffle test
Using network 'development'.
start testing
Contract: Conference
✓ Initial conference settings should match (191ms)
✓ Should update quota (174ms)
✓ Should let you buy a ticket (717ms)
✓ Should issue a refund by owner only (714ms)
4 passing (2s)
编写网络应用程序
在会议目录下执行npm init,然后一路回车,会生成一个名为package.json的文件,编辑这个文件,在scripts部分添加两条命令,最终结果如下:
{
"name": "conference",
"version": "1.0.0",
"description": "",
"main": "truffle-config.js",
"directories": {
"test": "test"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "webpack",
"server": "webpack-dev-server --open"
},
"author": "",
"license": "ISC"
}
package.json文件定义了本项目所需的各个模块,以及项目配置信息(如名称、版本、许可证等元数据)。 npm命令会根据这个配置文件自动下载所需的模块,即配置项目所需的运行和开发环境。
然后在conference目录下新建app目录,并新建index.html文件,如下:
Conference DApp2
Conference DApp
Contract deployed at:
Organizer:
Quota:
Registrants: 0
然后在app目录下创建javascripts目录和styleheets目录,分别存放js脚本文件和css样式文件。 真正与合约交互的是脚本文件。
脚本文件名为app.js,部分代码如下:
import "../stylesheets/app.css";
import { default as Web3 } from 'web3';
import { default as contract } from 'truffle-contract';
import conference_artifacts from '../../build/contracts/Conference.json'
var accounts, sim;
var Conference = contract(conference_artifacts);
window.addEventListener('load', function() {
//alert("aaaaa");
// Checking if Web3 has been injected by the browser (Mist/MetaMask)
if (typeof web3 !== 'undefined') {
console.warn("Using web3 detected from external source. If you find that your accounts don't appear or you have 0 MetaCoin, ensure you've configured that source properly. If using MetaMask, see the following link. Feel free to delete this warning. :) http://truffleframework.com/tutorials/truffle-and-metamask")
// Use Mist/MetaMask's provider
window.web3 = new Web3(web3.currentProvider);
} else {
console.warn("No web3 detected. Falling back to http://localhost:8545. You should remove this fallback when you deploy live, as it's inherently insecure. Consider switching to Metamask for development. More info here: http://truffleframework.com/tutorials/truffle-and-metamask");
// fallback - use your fallback strategy (local node / hosted node + in-dapp id mgmt / fail)
window.web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));
}
Conference.setProvider(web3.currentProvider);
App.start();
$("#changeQuota").click(function() {
var newquota = $("#confQuota").val();
App.changeQuota(newquota);
});
// Wire up the UI elements
});
...
这段代码我不打算过多解释,主要就是用JS加上wweb3 API调用合约的功能。
至此,web部分基本准备好了,我们只需要使用webpack打包部署即可。 Webpack 打包还需要一个名为 webpack.config.js 的配置文件。 这个文件告诉webpack打包的规则以太坊web开发,涉及到webpack的使用。 我不会在这里解释太多。
打包和部署 Web 应用程序
包部署需要安装webpack及相关组件。 安装方式有两种:全局安装和本地安装。 所谓部分安装,就是将组件全部安装在项目目录下(conference/node_modules)。 我这里使用的是部分安装。 根据我们项目的实际情况,需要安装以下组件,
npm install --save-dev webpack@3.0.0
npm install babel-loader --save-dev
npm install babel-core --save-dev
npm install html-loader --save-dev
npm install --save-dev webpack-dev-server@2.11.0
npm install html-webpack-plugin --save-dev
npm install truffle-contract --save-dev
npm install --save-dev style-loader css-loader
环境已安装并准备打包。
$ sudo npm run start
> conference@1.0.0 start /home/pony/ethereum/conference
> webpack
Hash: ec8b764f75c05b477d9d
Version: webpack 3.0.0
Time: 2686ms
Asset Size Chunks Chunk Names
bundle.js 3.36 MB 0 [emitted] [big] main
./index.html 740 bytes [emitted]
[10] (webpack)/buildin/global.js 509 bytes {0} [built]
[16] (webpack)/buildin/module.js 517 bytes {0} [built]
[47] ./app/javascripts/app.js 3.85 kB {0} [built]
[48] ./app/stylesheets/app.css 1.08 kB {0} [built]
[49] ./node_modules/css-loader!./app/stylesheets/app.css 413 bytes {0} [built]
[175] ./build/contracts/Conference.json 71.1 kB {0} [built]
+ 170 hidden modules
Child html-webpack-plugin for "index.html":
[0] ./node_modules/html-webpack-plugin/lib/loader.js!./app/index.html 706 bytes {0} [built]
如果没有报错,进入build目录,可以看到bundle.js和index.html两个文件,这是最终打包好的网页文件。
然后部署,
$ sudo npm run server
> conference@1.0.0 server /home/pony/ethereum/conference
> webpack-dev-server --open
Project is running at http://localhost:8080/
webpack output is served from /
Content not from webpack is served from ./build
404s will fallback to /index.html
Hash: ecae3662137376f80de0
Version: webpack 3.0.0
...
这相当于运行一个小型的 nodejs 服务器。 我们可以在浏览器中输入:8080/看看效果:
剪贴板.png
可以看到合约的发布地址和会议组织者的地址(msg.sender)已经显示成功,可以通过点击更改按钮更改quota的值。
我已经将这篇文章的代码上传到github。
参考