本文内容来自熊丽兵老师在登链学院上的《以太坊Dapp开发实战》课程
简介
本文为一个简单的去中心化应用的开发,旨在了解以太坊Dapp开发流程。
应用效果图如下
第一个去中心化应用.png应用的功能很简单
浅蓝色部分用来显示区块链上的姓名和年龄信息
浅绿色部分用来修改区块链上的姓名和年龄信息
开发流程
本例在Ubuntu系统下开发,据说在windows下会出现莫名其妙的问题,所以没用。
本开发示例没有使用任何框架,后续会写truffle框架开发示例
准备:选择以太坊网络节点、钱包连接节点、remix连接节点
后端:智能合约开发 -> 智能合约测试 -> 智能合约部署
前端:安装web服务器 -> 前端UI设计
交互:web3与智能合约交互
本例的工具选择
以太坊网络节点:ganache虚拟节点
钱包:metaMask
代码编辑器:Remix(以太坊在线IDE)
web服务器:lite-server
web3版本:web3.js
准备
选择一个以太坊网络节点,然后将钱包和remix跟此节点连接起来,打通环境
选择以太坊网络节点
以太坊的节点有很多种:主网、测试网络、geth私链节点、ganache模拟节点
因为每个交易都需要花钱,这在开发环境下非常不适合,所以开发时不要选择以太坊的主网,这会花费真实的以太币,也不要选择以太坊的测试网络,因为要等待区块的确认,这个过程会占用时间,而开发需要及时反馈。
这里选择ganache模拟节点
安装ganache
ganache有CLI和GUI两个版本,本文安装的是CLI版本。github地址:https://github.com/trufflesuite/ganache-cli
GUI版本地址:https://github.com/trufflesuite/ganache/releases ,如果想使用图形界面版,选择对应版本下载安装即可
sudo npm install -g ganache-cli //需要先安装nodejs
开启ganache
智能合约的测试部署需要在节点上进行,所以这里开启ganache节点。可以单独开一个终端运行ganache
ganache-cli
钱包连接ganache节点
以太坊Dapp交易需要花钱,钱存储在钱包里。所以,需要用到钱包。这里使用最常用的MetaMask钱包
MetaMask(官网:https://metamask.io/ )是一款浏览器插件钱包,不需下载安装客户端,只需添加至浏览器扩展程序即可使用。它不仅是一个简单的钱包,还可以很方便的调试和测试以太坊的智能合约。
安装MetaMask
安装可参考此链接:以太坊钱包MetaMask使用教程。基本的使用方法文章里都有介绍
连接ganache节点
点击MetaMask的NetWork栏,选择Private Network(ganache节点:localhost 8545),即可连接ganache节点
导入ganache账户
点击账户栏,选择 Import Account,输入私钥(启动ganache时会列出十个账户和对应的私钥,选择一个私钥复制过来)即可导入ganache自动创建的账户到MetaMask中。此账户中会默认有100ETH。用此账户来部署合约以及交易。
Remix连接ganache节点
Remix的Run界面的Environment
选项里选择web3 Provider
,弹出的窗口里输入ganache-cli的监听url(http://localhost:8545) ,即可连接上ganache节点
注意:remix中的使用的账户和MetaMask中使用的账户要一致
remix默认使用ganache创建的第一个账户,可以点击Account处更换
MetaMask导入账户时可直接导入第一个账户,就可与remix中的账户对应。
后端开发
智能合约开发使用以太坊的在线IDERemix
Remix使用请参考:教程 | 【Ethereum 智能合约开发笔记】使用 Remix
Remix编译版本要和智能合约的版本一致,否则会报错。
如智能合约使用0.4.24,那么remix也要选择0.4.24(Compile页面里选择)
智能合约开发
simple.sol
pragma solidity ^0.4.24;
contract simple{
string name;
uint age;
//定义事件
event Instructor(string name, uint age);
function set(string _name, uint _age) public {
name = _name;
age = _age;
//触发事件
emit Instructor(name, age);
}
function get() public view returns(string, uint) {
return (name, age);
}
}
智能合约测试
这里不太好测试,后面用truffle时可以很方便的进行测试。要记住,Dapp开发一定要进行测试!这直接关系到钱!
智能合约部署
remix的Run页面里点击Deploy(create)按钮,即可把智能合约部署到节点上
在Deployed Contracts里会看到set和get函数。可以跟智能合约交互
set后面的输入框里输入"中本聪",18
,然后点击set按钮。就将信息写入了区块链,然后点击get按钮,刚才输入的信息就会显示出来。
前端开发
项目目录结构
|-- simple //项目根目录
-- index.html
-- index.css
-- index.js
安装web服务器环境
项目开发中,环境的一致性非常重要,这里给项目本身安装web服务器(lite-server),而不需依赖外部的web服务器(如nginx)
npm install lite-server --save-dev
安装完后会在项目根目录下生成node_modules
目录
|-- simple //项目根目录
-- index.html
-- index.css
-- index.js
|-- node_modules
在终端开启服务
node_modules/lite-server/bin/lite-server
UI设计完后,开启服务后会自动打开网页,就会看到html内容
UI设计
基本的UI设计跟传统的App开发一样。
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>第一个去中心化应用</title>
<link rel="stylesheet" href="./index.css">
</head>
<body>
<div id="content">
<h1 id="title">第一个去中心化应用</h1>
<h2 id="info"></h2>
<div id="loader"></div>
<div id="update">
<div>
<label for="name">姓名:</label>
<input type="text" id="name">
</div>
<div>
<label for="age">年龄:</label>
<input type="text" id="age">
</div>
<button id="button">更新</button>
</div>
</div>
</body>
</html>
index.css
body{background:#f0f0f0;}
#content{width:350px;margin:0 auto;}
#title{text-align: center;}
#info{padding:0.5em;background: lightblue;margin:1em 0;}
#update{padding:1em;background: lightgreen}
#name{border:none;}#age{border:none;}
button{margin:1em 0;}
web3与智能合约交互
这里是Dapp的关键部分,前端与智能合约使用RPC协议来交互。web3封装了RPC,提供了更友好的接口来调用.
web3有很多实现版本,用的最多的使web3.js。本例使用的就是web3.js。github地址:https://github.com/ethereum/web3.js ,详细信息可查看文档
大体步骤如下
获取web3对象 -> 得到智能合约实例 -> 调用智能合约方法来交互
修改html页面,在body
最后引入js文件
<!-- 引入jquery -->
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
<!-- 引入web3.js 这里的web3.js为0.2版本。1.0版本目前还是beta阶段,等稳定了可更换为1.0版本 -->
<script src="https://cdn.jsdelivr.net/gh/ethereum/web3.js/dist/web3.min.js"></script>
<!-- 引入index.js -->
<script src="./index.js"></script>
index.js
//设置provider(web3连接到哪个节点)
if (typeof web3 !== 'undefined') {
web3 = new Web3(web3.currentProvider);
} else {
// Set the provider you want from Web3.providers
web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));
}
//得到智能合约实例
//数组里是智能合约的abi。修改智能合约的话abi也会变化,需要更换
var infoContract = web3.eth.contract([
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"name": "name",
"type": "string"
},
{
"indexed": false,
"name": "age",
"type": "uint256"
}
],
"name": "Instructor",
"type": "event"
},
{
"constant": false,
"inputs": [
{
"name": "_name",
"type": "string"
},
{
"name": "_age",
"type": "uint256"
}
],
"name": "set",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "get",
"outputs": [
{
"name": "",
"type": "string"
},
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
}
])
//地址为部署的智能合约的地址,重新部署的话地址就会改变,需要用新的合约地址
var simple = infoContract.at('0xa2eefd5ee8a78630d27e3b884b04b53315881942');
//调用合约的方法进行交互。交易是异步的,需要用回调函数来接收结果。结果在result里
simple.get.call(function(error,result){
if(!error){
$("#info").html(`我叫` + result[0] + `, 我今年` + result[1] + `岁了。`);
}
});
//点击更新按钮,更新信息
$("#button").click(function(){
$("#loader").show();
simple.set.sendTransaction($("#name").val(),$("#age").val(),function(error,result){
if(!error){
console.log("set ok");
}
})
});
//监听事件,实时更新,而不是手动刷新浏览器更新。对应智能合约中自定义的event事件
var infoEvent = simple.Instructor();
infoEvent.watch(function(error,result){
if(!error){
$("#loader").hide();
$("#info").html(`我叫` + result.args.name + `, 我今年` + result.args.age + `岁了。`);
}else{
$("#loader").hide();
$("#info").html("Error:" + error);
}
})
结语
这是一个简单的Dapp开发示例,目的是熟悉以太坊Dapp开发流程。
此方式有个很大的缺点,就是web3与智能合约交互太麻烦,修改智能合约后需要手动修改abi和地址信息。而且也不容易测试。
实际开发Dapp都是使用truffle框架来开发。后续会写truffle开发示例。
网友评论