博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
DAPP开发初探——永存的留言
阅读量:4336 次
发布时间:2019-06-07

本文共 6772 字,大约阅读时间需要 22 分钟。

转载地址

前言

最近DAPP的开发貌似很火,学习了区块链的一些知识之后,相信有很多人和我一样,也想了解开发一个DAPP是一个怎样的流程。

下面将通过一个简单的栗子来初识一下DAPP的开发流程,届时,我们也将开发出第一个DAPP应用–《永存的留言》。

在线体验(Ludis):。

项目介绍

《永存的留言》是一个基于以太坊的在线留言平台。它的功能十分简单–用户可以在平台上进行留言,平台每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,体会了开发的基本流程。

  • 明确项目需求
  • 确定开发环境
  • 编写、测试、部署合约
  • 设计前端页面,使前后端交互
  • 发布测试

项目源码

参考文章

转载于:https://www.cnblogs.com/qq874455953/p/10264443.html

你可能感兴趣的文章
UIView的layoutSubviews,initWithFrame,initWithCoder方法
查看>>
STM32+IAP方案 实现网络升级应用固件
查看>>
用74HC165读8个按键状态
查看>>
jpg转bmp(使用libjpeg)
查看>>
linear-gradient常用实现效果
查看>>
sql语言的一大类 DML 数据的操纵语言
查看>>
VMware黑屏解决方法
查看>>
JS中各种跳转解析
查看>>
JAVA 基础 / 第八课:面向对象 / JAVA类的方法与实例方法
查看>>
Ecust OJ
查看>>
P3384 【模板】树链剖分
查看>>
Thrift源码分析(二)-- 协议和编解码
查看>>
考勤系统之计算工作小时数
查看>>
4.1 分解条件式
查看>>
Equivalent Strings
查看>>
flume handler
查看>>
收藏其他博客园主写的代码,学习加自用。先表示感谢!!!
查看>>
H5 表单标签
查看>>
su 与 su - 区别
查看>>
C语言编程-9_4 字符统计
查看>>