编辑推荐: |
本文通过一个简单的例子来初识一下DAPP的开发流程,希望对您有所帮助
本文来自于简书,由火龙果软件Delores编辑、推荐。 |
|
项目介绍
《永存的留言》是一个基于以太坊的在线留言平台。它的功能十分简单–用户可以在平台上进行留言,平台每10s随机的展示留言内容。
但是它的特点在于,利用区块链的特性,保证了数据的真实性、完整性和安全性
使用Solidity开发后端方法
使用Truffle框架
基于unbox react脚手架项目
部署在以太坊测试网络上Ropoetn Test Network
使用MetaMask钱包插件发布交易
开发步骤
下载react项目模板
确保本地已经准备好Truffle所需的环境,准备以下命令,下载react项目模板。
$ mkdir a && cd a
truffle unbox react
当看到 Unbox successful. Sweet!提示时,表明下载成功。
编写智能合约
这是我们唯一的实现合约,包含的发送留言和读取留言的方法。
pragma solidity
^0.4.19;
contract SimpleStorage {
// 留言结构体
struct Message {
string word; // 留言
address from; // 留言者地址
string timestamp ; // 留言unix时间戳
}
Message[] private wordArr;
/**
* 写入留言的方法
*/
function setWord(string s, string t) public {
wordArr.push(Message({
word: s,
from: msg.sender,
timestamp: t
}));
}
/**
* 获取随机留言的方法
*/
function getRandomWord(uint random) public view
returns (uint, string, address, string) {
if(wordArr.length==0){
return (0, "", msg.sender, "");
}else{
Message storage result = wordArr[random];
return (wordArr.length, result.word, result.from,
result.timestamp);
}
}
}
|
编译、部署合约
修改发布的脚本。
var SimpleStorage
= artifacts.require
("./SimpleStorage.sol");
//var Words = artifacts.require("Words");
module.exports = function(deployer) {
deployer.deploy(SimpleStorage);
//deployer.deploy(Words);
}; |
执行truffle compile进行合约的编译。
获取合约地址。
这里我们打开MetaMask钱包插件,左上角选择Ropoetn Test Network网络.
利用Remix编译,发布合约到以太坊测试环境。
通过MetaMask的交易hash查询,获取已经部署到以太坊测试网络中的合约地址。
编写前端页面
这个部分主要是编写前端的展示效果和与合约交互的逻辑,这一部分最难编写,也最耗时间。
主要逻辑代码
const contractAddress
=
"0x39e5196750dcddb1aaf6dda7d6e8dbb633482905"
// 合约地址(以太坊测试网络)
var simpleStorageInstance // 合约实例
class App extends Component {
// 初始化构造
constructor(props) {
super(props)
this.state = {
word: null,
from: null,
timestamp: null,
random: 0,
count: 0,
input: '',
web3: null,
emptyTip: "还没有留言, 快来创建全世界第一条留言吧~",
firstTimeLoad: true,
loading: false,
loadingTip: "留言正在写入,请耐心等待~",
waitingTip: "留言正在写入,请耐心等待~",
successTip: "留言成功",
animate: "",
in: css(styles.in),
out: css(styles.out)
}
}
// 获取Web3实例
componentWillMount() {
// Get network provider and web3 instance.
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 simpleStorage = contract (SimpleStorageContract)
simpleStorage.setProvider (this.state.web3.currentProvider)
// Get accounts.
this.state.web3.eth.getAccounts ((error, accounts)
=> {
simpleStorage.at(contractAddress). then(instance
=> {
simpleStorageInstance = instance
/*simpleStorage.deployed(). then((instance) =>
{
simpleStorageInstance = instance // 部署本地Ganache*/
console.log("合约实例获取成功")
})
.then(result => {
return simpleStorageInstance.getRandomWord (this.state.random)
})
.then(result => {
console.log("读取成功", result)
if(result[1]!=this.setState.word){
this.setState({
animate: this.state.out
})
setTimeout(() => {
this.setState({
count: result[0].c[0],
word: result[1],
from: result[2],
timestamp: result[3],
animate: this.state.in,
firstTimeLoad: false
})
}, 2000)
}else{
this.setState({
firstTimeLoad: false
})
}
this.randerWord()
})
})
}
// 循环从区块上随机读取留言
randerWord() {
setInterval(() => {
let random_num = Math.random() * (this.state.count?
this.state.count: 0)
this.setState({
random: parseInt(random_num)
})
console.log("setInterval读取", this.state.random)
simpleStorageInstance.getRandomWord (this.state.random)
.then(result => {
console.log("setInterval读取成功", result)
if(result[1]!=this.setState.word){
this.setState({
animate: this.state.out
})
setTimeout(() => {
this.setState({
count: result[0].c[0],
word: result[1],
from: result[2],
timestamp: result[3],
animate: this.state.in
})
}, 2000)
}
})
}, 10000)
}
// 写入区块链
setWord(){
if(!this.state.input) return
this.setState({
loading: true
})
let timestamp = new Date().getTime()
simpleStorageInstance.setWord (this.state.input,
String(timestamp), {from: this.state.web3.eth.accounts[0]})
.then(result => {
this.setState({
loadingTip: this.state.successTip
})
setTimeout(() => {
this.setState({
loading: false,
input: '',
loadingTip: this.state.waitingTip
})
}, 1500)
})
.catch(e => {
// 拒绝支付
this.setState({
loading: false
})
})
}
// 时间戳转义
formatTime(timestamp) {
let date = new Date(Number(timestamp))
let year = date.getFullYear()
let month = date.getMonth() + 1
let day = date.getDate()
let hour = date.getHours()
let minute = date.getMinutes()
let second = date.getSeconds()
let fDate = [year, month, day, ]. map(this.formatNumber)
return fDate[0] + '年' + fDate[1] + '月' + fDate[2]
+ '日' + ' ' + [hour, minute, second].map (this.formatNumber).join(':')
}
/** 小于10的数字前面加0 */
formatNumber(n) {
n = n.toString()
return n[1] ? n : '0' + n
}
} |
运行项目
使用npm start启动项目,浏览器的3000端口运行。
效果如下(一定要连接到Ropoetn Test Network网络才可以)。
总结
这样我们就开发出了我们的第一个DAPP,体会了开发的基本流程。
明确项目需求
确定开发环境
编写、测试、部署合约
设计前端页面,使前后端交互
发布测试
|