阐明:本篇所波及的DAPP众筹需要及合约实现来自登链社区
在后面的众筹案例中,创作者没有方法查看到所有参与者,有两个方法能够实现查案所有参与者:
- 退出一个状态变量:address[] joinAccounts,这是一个数组,用来记录所有参与者的地址,每当有新的参与者进来时,往数组中退出参与者地址。
- 通过触发事件把参与者地址记录到日志中,而后启动一个服务程序监听事件,当事件触发时,把参与者地址记录到数据库中,并提供一个后端服务,把数据库中的参与者列表返回给前端。
两种办法各有优缺点:办法1的gas耗费会远高于办法2,长处是不须要额定引入服务器;办法2则相同,应用事件的办法2其实还有一个益处,就是能够实时监听到事件的变动(通常对应着链上状态的变动),这在一些场合十分有用。
上面次要介绍办法2,通过后盾服务,监听事件变动。咱们应用Node.js及Express框架作为后盾服务。
装置服务端环境
进入crowdfunding工程目录,创立server目录作为后端工程目录,并装置环境:
mkdir server
cd server
npm init
npm install express --save
新建一个文件index.js,编写服务端程序:
const express = require('express')
const app = express()
app.get('/', (req, res) => res.send('Hello World'))
app.listen(3000, () => console.log('Start Server, listening on port 3000!'))
下面代码,引入了express模块,它在后盾常驻运行,并监听3000端口,当客户端发动申请后,响应“Hello World”字符串。
启动后端服务:
node index.js
启动后,在浏览器拜访http://localhost:3000,就能够看到Hello World!
常驻服务监听合约事件
先批改Crowdfunding合约,退出一个事件。而后在receive函数中触发该事件:
contract Crowdfunding {
...
// address[] joinAccouts;
event Join(address indexed user, uint price);
...
// 用户向合约转账时,触发的回调函数
receive() external payable {
...
emit Join(msg.sender, msg.value); // 48820 gas
}
...
}
批改完合约后,应用truffle migrate –reset从新编译部署。
回到后端,在server目录下装置web3:
npm install web3 --save
而后批改index.js,退出监听Join事件的代码:
// express 启动代码
...
// 引入web库
var Web3 = require('web3');
// 应用WebSocket协定 连贯节点
let web3 = new Web3(new Web3.providers.WebsocketProvider('ws://localhost:7545'));
// 获取合约实例
var Crowdfunding = require('../build/contracts/Crowdfunding.json');
const crowdFund = new web3.eth.Contract(
Crowdfunding.abi,
Crowdfunding.networks[5777].address
);
// 监听Join事件
crowdFund.events.Join(function(error, event) {
if (error) {
console.log(error);
}
// 打印出交易hash 及区块号
console.log("交易hash:" + event.transactionHash);
console.log("区块高度:" + event.blockNumber);
// 取得监听到的数据:
console.log("参加地址:" + event.returnValues.user);
console.log("参加金额:" + event.returnValues.price);
});
在初始化web3时,应用了WebsocketProvider,通过WebSocket通信协议与节点通信,如果是应用Geth节点,须要应用–ws开启服务,开发应用的Ganache默认开启了WebSocket服务。
重新启动后盾服务:
node index.js
启动前端服务:
npm run serve
在浏览器里拜访http://localhost:8080,进入前端页面,点击“参加众筹”(如果以后账户参加过,就切换不同账号参加众筹),切换到后端的命令行控制台窗口,能够看到打印出日志:
交易hash:0xe45848494c6990469db6de4485708ffb72d2d27bbc64cde92ff67d11394176ad
区块高度:6
参加地址:0xa75a4da940a2dDcE9db7e4FbCC62e236558DbEaA
参加金额:20000000000000000
为了方便管理,咱们能够把这部分业务数据写入到中心化的数据库里。
MySql数据库环境筹备
装置Mysql数据库,并创立以下数据库和表来存储众筹数据:
CREATE DATABASE crowdfund;
use crowdfund;
CREATE TABLE joins(
id INT UNIQUE AUTO_INCREMENT,
address VARCHAR(42) UNIQUE,
price FLOAT NOT NULL,
tx VARCHAR(66) NOT NULL,
block_no INT NOT NULL,
created_at datetime,
PRIMARY KEY (id)
);
监听数据入库
给后盾装置node-mysql驱动:
cd server
npm install mysql --save
批改index.js,引入mysql,并退出一个插入数据库函数:
var mysql = require('mysql');
function getConn() {
return mysql.createConnection({
host : 'localhost',
user : 'root',
password : '123456',
port : '3306',
database : 'crowdfund'
});
}
function insertJoins(address, price, tx, blockNo) {
// 连贯数据库
var connection = getConn();
connection.connect();
// 构建插入语句
const query = `INSERT into joins (
address,
price,
tx,
block_no,
created_at
) Values (?,?,?,?,NOW())`;
const params = [address, price, tx, blockNo];
// 执行插入操作
connection.query(query, params, function (error, results) {
if (error) throw error;
// console.log('results=> ' + results);
});
connection.end();
}
并在监听打印日志的前面调用insertJoins()函数:
// 监听Join事件
crowdFund.events.Join(function(error, event) {
...
insertJoins(event.returnValues.user,
// 把以wei为单位的价格转为ether单位
web3.utils.fromWei(event.returnValues.price),
event.transactionHash,
event.blockNumber)
});
重启后盾服务:
node index.js
在DAPP前端页面单击“参加众筹”后(如果以后账户参加过,就切换不同账号参加众筹),如果一切正常,就能够在数据库查问到相应的众筹记录:
为前端提供众筹记录显示
通过读取数据库的数据,并在Express退出一个路由,承受前端申请后返回读取到的数据,在index.js先退出一个getJoins()函数来读取数据库数据:
// 通过一个回调函数把后果返回进来
function getJoins(callback) {
// 获取数据库链接
var connection = getConn();
connection.connect();
// 查问 SQL
const query = `SELECT address, price from joins`;
const params = [];
// 查询数据库
connection.query(query, params, (err, rows)=>{
if(err){
return callback(err);
}
console.log(`result=>`, rows);
callback(rows);
});
connection.end();
}
退出一个新路由/joins:
app.get('/joins', (req, res) => {
getJoins( rows=> {
// 设置容许跨域拜访
res.set({'Access-Control-Allow-Origin': '*'})
.send(rows)
});
})
重启后端服务,浏览器拜访http://localhost:3000/joins,能够看到返回参加众筹的JSON数据:
后端筹备好了后,接下来咱们让前端通过Ajax申请拜访http://localhost:3000/joins接口获取众筹数据列表。
在前端我的项目根目录下,装置axios:
npm install axios
批改CrowdFund.vue,退出获取众筹列表的getJoins()函数:
...
import axios from 'axios';
export default {
name: 'CrowdFund',
data() {
return {
...
joinList: [],
};
},
// 以后Vue组件被创立时回调的hook 函数
async created() {
...
this.getJoins()
},
methods: {
...
// 获取众筹列表
getJoins() {
axios.get('http://localhost:3000/joins')
.then(response => {
this.joinList = response.data
})
.catch(function (error) { // Ajax申请失败解决
console.log(error);
});
},
}
}
最初还须要在HTML模板中退出joinList的渲染:
<!-- 如果是创作者,显示 -->
<div class="box" v-if="isAuthor">
<div >
<p v-bind:key="item" v-for="item in joinList" >
<label> 地址:{{ item.address.substring(0, 30) + "..." }}</label>
金额:<b> {{ item.price }} </b>
</p>
</div>
<button :disabled="closed" @click="withdrawFund"> 提取资金</button>
</div>
启动前端利用:
npm run serve
浏览器拜访http://localhost:8000,在MetaMask中切换到创作者账号,刷新浏览器后能够看到输入的众筹列表:
在众筹DAPP案例中,咱们通过Vue.js开发利用前端,应用Node.js后端监控合约事件,并将一些外围业务数据用中心化数据库进行了存储。这就囊括了所有在DAPP开发中波及的内容了。
发表回复