關(guān)于eosjs智能合約開發(fā)近她,分為三個步驟:
一、概念了解膳帕、學(xué)習(xí)粘捎,查找文檔階段:具體查看文檔如下
https://blog.csdn.net/weixin_39842528/article/details/81098715????????eosjs前端簡明使用手冊,包含鏈接私鏈方法和部分eosjs封裝好的方法
https://eos.readthedocs.io/zh_CN/latest/API/EOSIO-RPC/????????????????eosio-EOS官方中文文檔危彩,包含用到的接口及范例
https://developers.eos.io/eosio-nodeos/reference#get_info????????????????nodeos官方文檔攒磨,包含用到的接口
二、搭建node服務(wù)汤徽,npm引入所需要使用的代碼咧纠,鏈接私鏈,調(diào)試部分接口
搭建node服務(wù):代碼如右側(cè)所示泻骤,詳見:https://blog.csdn.net/zach_zhou/article/details/72779762
npm 引入 :
????1. 引入eos:npm install eos
????2.引入eosjs:npminstall eos-js
????3.引入express(node服務(wù)搭建所需):npm install express -save
????私鏈鏈接:方法詳見文章https://blog.csdn.net/weixin_39842528/article/details/81098715
方法調(diào)試:此時分兩種調(diào)試方法漆羔,
????1. 直接進行接口的調(diào)試梧奢,搭建界面之后,直接使用jQuery提供的ajax演痒,鏈接私鏈上的方法名(方法名鏈接方式詳見文章:https://developers.eos.io/eosio-nodeos/reference#get_info)亲轨,利用這種方法可直接進行私鏈上部分方法接口的聯(lián)調(diào)測試,但是需要和服務(wù)端提供私鏈的人員進行體檢溝通好鸟顺,這種方法會產(chǎn)生跨域的問題惦蚊,目前解決方案:使用nginx進行代理。
????2.使用node服務(wù)讯嫂,用eosjs提供的方法蹦锋,直接進行接口的測試并獲取數(shù)據(jù)和操作數(shù)據(jù),唯一的問題就是需要直接依賴node服務(wù)欧芽,否則無法跑通(目前使用此種方法進行測試)莉掂,方法詳見:https://blog.csdn.net/weixin_39842528/article/details/81098715
三、demo搭建
根據(jù)設(shè)計圖進行前端界面的搭建千扔,同時需要使用node便捷服務(wù)端接口供前端使用憎妙,但是在搭建的過程中,需要引入用戶的私鑰并進行一定的簽名算法才可以曲楚,具體node服務(wù)端代碼如下所示:
//引入http模塊
var http = require("http");
var express = require("express");
var app = express();
//app.use(bodyParser.urlencoded({
// extended: false
//}));
//設(shè)置主機名
var hostName = '192.168.1.111';
//設(shè)置端口
var port = 8989;
const {
Api,
JsonRpc,
RpcError,
JsSignatureProvider
} = require('eosjs');
const fetch = require('node-fetch'); // node only; not needed in browsers
const {
TextDecoder,
TextEncoder
} = require('text-encoding'); // node, IE11 and IE Edge Browsers
let defaultPrivateKey = "----"; ????// 提供的用戶的私鑰
let signatureProvider = new JsSignatureProvider([defaultPrivateKey]);;
const rpc = new JsonRpc('http://127.0.0.1:8888', {? ? ? ? ? ? ? ? ? // 內(nèi)部私鏈的ip訪問地址和端口號
fetch
});
const api = new Api({
rpc,
signatureProvider,
textDecoder: new TextDecoder(),
textEncoder: new TextEncoder()
});
//創(chuàng)建服務(wù)
app.all('*', function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
res.header("X-Powered-By", ' 3.2.1')
res.header("Content-Type", "application/json;charset=utf-8");
next();
});
/**
* 創(chuàng)建廣告
*/
app.post("/myservice/post", function(req, res) {
req.on('data', function(data) {
obj = JSON.parse(data);
console.log(obj);
(async() => {
const result = await api.transact({
actions: [{
account: 'adshow',? ? ? ? ? ? ? ? ? ? //賬戶
name: 'create',? ? ? ? ? ? ? ? ? ? ? ? ? ?//私鏈提供的方法名稱厘唾,問區(qū)塊鏈開發(fā)者
authorization: [{
actor: 'yan2',? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //操作者,需要對應(yīng)上面的私鑰
permission: 'active',? ? ? ? ? ? ? ? ? ? //對應(yīng)的權(quán)限龙誊,需要問區(qū)塊鏈開發(fā)者
}],
data:?obj,? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //該接口需要的數(shù)據(jù)
}]
}, {
blocksBehind: 3,
expireSeconds: 30,
});
res.send(result);
})();
})
});
/**
* 編輯廣告答案接口
*/
app.post('/myservice/edit', function(req, res) {
console.log('===============');
req.on('data', function(data) {
var obj = JSON.parse(data);
console.log(obj);
(async() => {
const result = await api.transact({
actions: [{
account: 'adshow',
name: 'edtarticanse',
authorization: [{
actor: 'yan2',
permission: 'active',
}],
data: obj
}]
}, {
blocksBehind: 3,
expireSeconds: 30,
});
res.send(result);
})();
})
})
/**
* 支付廣告?zhèn)蚪?/p>
*/
/**報錯:需要確定**/
app.post('/myservice/payMoney', function(req, res) {
console.log('===============');
req.on('data', function(data) {
var obj = JSON.parse(data);
try {
(async() => {
const result = await api.transact({
actions: [{
account: 'adshow',
name: 'payasset',
authorization: [{
actor: 'yan2',
permission: 'active',
}],
data: obj
}]
}, {
blocksBehind: 3,
expireSeconds: 30,
});
res.send(result);
})();
} catch(e) {
console.log('\nCaught exception: ' + e);
if(e instanceof RpcError)
console.log(JSON.stringify(e.json, null, 2));
}
})
})
/**
* 用戶參與廣告抚垃、獲取廣告文件時調(diào)用
*/
/**詳見日志**/
app.post('/myservice/userGetG', function(req, res) {
console.log('===============');
req.on('data', function(data) {
var obj = JSON.parse(data);
(async() => {
const result = await api.transact({
actions: [{
account: 'adshow',
name: 'partake',
authorization: [{
actor: 'yan2',
permission: 'active',
}],
data: obj
}]
}, {
blocksBehind: 3,
expireSeconds: 30,
});
res.send(result);
})();
})
})
/**
* 用戶提交答案
*/
app.post('/myservice/userUpAnswer', function(req, res) {
????console.log('===============');
????req.on('data', function(data) {
????????var obj = JSON.parse(data);
????????console.log(obj);
????????(async() => {
????????const result = await api.transact({
????????actions: [{
????????????account: 'adshow',
????????????name: 'uploadadanse',
????????????authorization: [{
????????????actor: 'yan2',
????????????permission: 'active',
????????}],
????????data: obj
????????}]
????}, {
????????blocksBehind: 3,
????????expireSeconds: 30,
????});
????res.send(result);
????})();
????})
})
app.listen(port, hostName, function() {
console.log(`服務(wù)器運行在http://${hostName}:${port}`);
});
四、前端界面
前端界面本人采用vue搭建趟大,也可以使用單純的js或者jQuery方法讯柔,node服務(wù)接口調(diào)用和平常調(diào)用Java接口方式一樣
總結(jié):由于對eos不了解,在學(xué)習(xí)的過程中遇到了很多坑护昧,主要表現(xiàn)在一下幾點:
?1.在連接上內(nèi)部私鏈之后,進行eosjs方法的調(diào)試粗截,發(fā)現(xiàn)部分方法無法獲取數(shù)據(jù)惋耙,無法走通。解決方法:經(jīng)過排查發(fā)現(xiàn)內(nèi)部私鑰沒有進行簽名算法加密熊昌,同時和用于名無法對應(yīng)绽榛,在經(jīng)過修改之后,方法跑通婿屹。(已解決)
?2. 服務(wù)端權(quán)限問題:獲取數(shù)據(jù)時灭美,采用的用戶權(quán)限不同,會導(dǎo)致方法無法走通昂利,此時需要讓服務(wù)端修改用戶權(quán)限届腐,才能正常獲取數(shù)據(jù)以及修改數(shù)據(jù)铁坎。(已解決)
?3. node服務(wù)問題:在使用接口進行調(diào)試時,需要使用node搭建一個屬于自己的服務(wù)端進行連接犁苏,并提供響應(yīng)的接口給前端硬萍,讓前端自行調(diào)用。(已解決)
?4. 在接口調(diào)用的過程中围详,由于瀏覽器同源策略問題朴乖,會產(chǎn)生跨域的問題,目前解決方法是采用nginx進行代理轉(zhuǎn)發(fā)助赞。(已解決)
?5. 用戶私鑰加密問題:目前demo中用戶以及用戶對應(yīng)的私鑰是配置在服務(wù)端的买羞,在動態(tài)獲取私鑰并進行加密過程中,服務(wù)端報錯雹食,錯誤未知畜普,目前暫時未找到問題所在。(據(jù)區(qū)塊鏈開發(fā)同事說婉徘,需要對接第三方https://www.mytokenpocket.vip/漠嵌,用戶導(dǎo)入私鑰之后,直接獲取到用戶的各種信息以供node服務(wù)端使用盖呼,但是暫時未接入儒鹿,方法是否可用為進行驗證)
?6.?在調(diào)用node服務(wù)接口過程中,發(fā)現(xiàn)在使用post方法時几晤,前端傳遞的參數(shù)服務(wù)端一直獲取不到约炎,后來經(jīng)過查找發(fā)現(xiàn)是服務(wù)在數(shù)據(jù)未接受到就已經(jīng)產(chǎn)生返回,此時就需要服務(wù)端進行數(shù)據(jù)的監(jiān)聽蟹瘾,如下:
app.post("/post", function(req, res) {
????req.on('data', function(data) {
????????obj = JSON.parse(data);
????????var dataList = {
????????????'message': '回傳成功'
????????}
????????res.send(dataList);
????})
})
前端傳遞過來的參數(shù)為字符串形式圾浅,需要進行一次轉(zhuǎn)換成JSON格式,然后后續(xù)的操作放在on監(jiān)聽事件內(nèi)部憾朴,包括接口返回send的數(shù)據(jù)狸捕。