
1,摘要
第六課 技術(shù)小白如何開(kāi)發(fā)一個(gè)DAPP區(qū)塊鏈應(yīng)用(以寵物商店為例)介紹了如何獲取寵物商店的TRUFLLE框架代碼,并完成部署的過(guò)程。
但是這個(gè)是已經(jīng)成熟的代碼框架,一般用戶要開(kāi)發(fā)自己的項(xiàng)目。那如何借用寵物商店成熟框架完成自有DAPP的搭建呢?我們以tiny熊老師的一個(gè)姓名/年齡智能合約用例來(lái)呈現(xiàn)方法。
2, 需求描述
我們要實(shí)現(xiàn)一個(gè)用戶姓名和年紀(jì)的輸入和呈現(xiàn)頁(yè)面,能更新智能合約上的用戶名和年齡。重新輸入用戶名和年紀(jì),點(diǎn)擊按鈕可更新智能合約的這2個(gè)變量信息。
3,操作步驟
3.1 創(chuàng)建目錄,下載框架
首先創(chuàng)建好目錄,下載寵物商店的代碼框架。
duncanwang@ubuntu:~/work$ mkdir name-age
duncanwang@ubuntu:~/work$ cd name-age
duncanwang@ubuntu:~/work/name-age$ truffle unbox pet-shop
Downloading...
Unpacking...
Setting up...
Unbox successful. Sweet!
Commands:
Compile: truffle compile
Migrate: truffle migrate
Test contracts: truffle test
Run dev server: npm run dev
duncanwang@ubuntu:~/work/name-age$
3.2 創(chuàng)建智能合約代碼
新建一個(gè)InfoContract.sol智能合約文件,并把它更新到./contracts目錄下。
pragma solidity ^0.4.24;
contract InfoContract {
string name;
uint age;
event Instructor(string name, uint age);
function setInfo(string _name, uint _age) public {
name = _name;
age = _age;
emit Instructor(name, age);
}
function getInfo() public view returns(string, uint) {
return (name, age);
}
}
3.3 增加合約相關(guān)的部署和測(cè)試代碼
1) 增加合約部署測(cè)試
文件2_info_contract.js到./migrations目錄,代碼如下,表示contract InfoContract合約部署。
var MyContract = artifacts.require("./InfoContract.sol");
module.exports = function(deployer) {
// deployment steps
deployer.deploy(MyContract);
};
2) 增加測(cè)試文件
pragma solidity ^0.4.24;
import "truffle/Assert.sol";
import "truffle/DeployedAddresses.sol";
import "../contracts/InfoContract.sol";
contract TestInfoContract {
InfoContract info = InfoContract(DeployedAddresses.InfoContract());
string name;
uint age;
function testInfo() {
info.setInfo("ABC", 10);
(name, age) = info.getInfo();
Assert.equal(name, "ABC", "設(shè)置名字出錯(cuò)");
Assert.equal(age, 10, "設(shè)置年齡出錯(cuò)");
}
}
- 修改配置文件
因?yàn)槟J(rèn)ganache-cli的端口為8545,所以需要修改truffle.js的端口號(hào)由7545 變?yōu)?545。
module.exports = {
// See <http://truffleframework.com/docs/advanced/configuration>
// for more about customizing your Truffle configuration!
networks: {
development: {
host: "127.0.0.1",
port: 8545,
network_id: "*" // Match any network id
}
}
};
否則測(cè)試時(shí)會(huì)有找不到客戶端提示。
duncanwang@ubuntu:~/work/name-age$ truffle test
Could not connect to your Ethereum client. Please check that your Ethereum client:
- is running
- is accepting RPC connections (i.e., "--rpc" option is used in geth)
- is accessible over the network
- is properly configured in your Truffle configuration file (truffle.js)
3.4 驗(yàn)收測(cè)試智能合約
1)參考寵物商店的文章代碼,在一個(gè)窗口啟動(dòng)一個(gè)ganache-cli 錢(qián)包。
duncanwang@ubuntu:~/work/name-age$ cd ..
duncanwang@ubuntu:~/work$ ganache-cli >>trace.log
2)編譯智能合約
然后啟動(dòng)另外一個(gè)窗口命令行,輸入一下命令。
duncanwang@ubuntu:~/work/name-age$ truffle compile
Compiling ./contracts/InfoContract.sol...
Compiling ./contracts/Migrations.sol...
Writing artifacts to ./build/contracts
智能合約驗(yàn)收命令。
測(cè)試成功的提示說(shuō)明:
duncanwang@ubuntu:~/work/name-age$ truffle test
Using network 'development'.
Compiling ./contracts/InfoContract.sol...
Compiling ./test/TestInfoContract.sol...
Compiling truffle/Assert.sol...
Compiling truffle/DeployedAddresses.sol...
Compilation warnings encountered:
/home/duncanwang/work/name-age/test/TestInfoContract.sol:12:4: Warning: No visibility specified. Defaulting to "public".
function testInfo() {
^ (Relevant source part starts here and spans across multiple lines).
TestInfoContract
? testInfo (838ms)
1 passing (5s)
3.5 完成前端頁(yè)面
完成以下2個(gè)文件的修改更新和上傳。
1) index.html
把寵物商店的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>First Truffle DApp Demo</title>
<link rel="stylesheet" type="text/css" href="main.css">
</head>
<body>
<div class="container">
<h1> First Truffle DApp Demo</h1>
<h2 id="info"></h2>
<img id="loader" src="https://loading.io/spinners/double-ring/lg.double-ring-spinner.gif">
<label for="name" class="col-lg-2 control-label">姓名:</label>
<input id="name" type="text">
<label for="name" class="col-lg-2 control-label">年齡:</label>
<input id="age" type="text">
<button id="button">更新</button>
</div>
<script src="http://libs.baidu.com/jquery/2.1.1/jquery.min.js"></script>
<script src="js/web3.min.js"></script>
<script src="js/truffle-contract.js"></script>
<script src="js/app.js"></script>
2) app.js
然后修改app.js的代碼,完成智能合約的執(zhí)行和調(diào)用作用。
App = {
web3Provider: null,
contracts: {},
init: function() {
return App.initWeb3();
},
/*加載web3*/
initWeb3: function() {
if (typeof web3 !== 'undefined') {
App.web3Provider = web3.currentProvider
web3 = new Web3(App.web3Provider);
} else {
App.web3Provider = new Web3.providers.HttpProvider("http://localhost:9545")
web3 = new Web3(App.web3Provider);
}
return App.initContract();
},
/*初始化合約,獲取合約,不需要使用at()的方式;
顯示合約的姓名和年齡信息*/
initContract: function() {
$.getJSON('InfoContract.json', function(data){
App.contracts.InfoContract = TruffleContract(data);
App.contracts.InfoContract.setProvider(App.web3Provider);
App.getInfo();
App.watchChanged();
});
App.bindEvents();
},
getInfo: function() {
App.contracts.InfoContract.deployed().then(function(instance) {
return instance.getInfo.call();
}).then(function(result) {
$("#loader").hide();
$("#info").html(result[0]+' ('+result[1]+' years old)');
console.log(result);
}).catch(function(err) {
console.error(err);
});
},
/*點(diǎn)擊按鈕更新姓名和年齡,則需要更新到智能合約上*/
bindEvents: function() {
$("#button").click(function() {
$("#loader").show();
App.contracts.InfoContract.deployed().then(function(instance) {
return instance.setInfo($("#name").val(), $("#age").val(), {gas: 500000});
}).then(function(result) {
return App.getInfo();
} ).catch(function(err) {
console.error(err);
});
});
},
watchChanged: function() {
App.contracts.InfoContract.deployed().then(function(instance) {
var infoEvent = instance.Instructor();
return infoEvent.watch(function(err, result) {
$("#loader").hide();
$("#info").html(result.args.name +' ('+ result.args.age +' years old)');
});
});
}
}
$(function(){
$(window).load(function() {
App.init();
});
});
3.6 測(cè)試驗(yàn)收前端和合約交互代碼
1) 部署合約
合約部署成功。
duncanwang@ubuntu:~/work/name-age$ truffle migrate
Using network 'development'.
Running migration: 1_initial_migration.js
Deploying Migrations...
... 0x5b3cd41a7fa7c58361172ac797412469a10edfbe721d8d81988f19282c9cb6e4
Migrations: 0x92b6ecd23aa98fad36926c12ec701f9aaa0933f4
Saving successful migration to network...
... 0x826fcd5b72b48435bf4f9941305727e52b0b7290631ba7b39f642027b1ee6947
Saving artifacts...
Running migration: 2_info_contract.js
Deploying InfoContract...
... 0x9943dd7b90207bd9fd1e85524d1d0227f18a92269d73f5a2141cb71c22dda1e9
InfoContract: 0x191391c710e1b632e40b4f2267dbc0f3bdb2bed4
Saving successful migration to network...
... 0x7e11f6e32585524e338e73439e4026c7c766625e5d23d56a4c90f8a11e5001ed
Saving artifacts...
2)安裝并啟動(dòng)lite-server
1] 安裝lite-server
【定義】lite-server 是輕量級(jí)的,僅適用于開(kāi)發(fā) 的 node 服務(wù)器, 它僅支持 web app。 它能夠?yàn)槟愦蜷_(kāi)瀏覽器, 當(dāng)你的html或是JavaScript文件變化時(shí),它會(huì)識(shí)別到并自動(dòng)幫你刷新瀏覽器, 還能使用套接字自動(dòng)注入變化的CSS, 當(dāng)路由沒(méi)有被找到時(shí),它將自動(dòng)后退頁(yè)面。
參考第一課 如何在WINDOWS環(huán)境下搭建以太坊開(kāi)發(fā)環(huán)境,完成MetaMask和liteServer的安裝。
duncanwang@ubuntu:~/work/name-age$ npm install lite-server --save-dev
成功安裝的輸出結(jié)果如下:
npm WARN pet-shop@1.0.0 No description
npm WARN pet-shop@1.0.0 No repository field.
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.2.4 (node_modules/fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.4: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"ia32"})
+ lite-server@2.4.0
added 342 packages from 273 contributors in 56.82s
2] 在新的窗口完成lite-server的啟動(dòng)。
duncanwang@ubuntu:~/work/name-age$ npm run dev
> pet-shop@1.0.0 dev /home/duncanwang/work/name-age
> lite-server
** browser-sync config **
{ injectChanges: false,
files: [ './**/*.{html,htm,css,js}' ],
watchOptions: { ignored: 'node_modules' },
server:
{ baseDir: [ './src', './build/contracts' ],
middleware: [ [Function], [Function] ] } }
[Browsersync] Access URLs:
--------------------------------------
Local: http://localhost:3000
External: http://10.225.18.149:3000
--------------------------------------
UI: http://localhost:3001
UI External: http://localhost:3001
--------------------------------------
[Browsersync] Serving files from: ./src
[Browsersync] Serving files from: ./build/contracts
[Browsersync] Watching files...
- 打開(kāi)主頁(yè)
輸入lite-server提示的主頁(yè)地址:http://10.225.18.149:3000
可以看到頁(yè)面輸出信息。

4)更新姓名和年齡
輸入框輸入姓名和年齡:王登輝,18 ,點(diǎn)擊更新按鈕,會(huì)彈出MEATMASK的交易提示,確認(rèn)交易。

確認(rèn)交易后,姓名和年齡信息會(huì)更新。

4,總結(jié)
本文僅從操作層面講解了如何利用寵物商店的模板樣例,快速重構(gòu)一個(gè)含前端的DAPP頁(yè)面。
具體WEB.3J的接口函數(shù)及定義,參考文章《第十一課 從寵物商店案例看DAPP架構(gòu)和WEB3.JS交互接口》。