經(jīng)過好一段時(shí)間的折騰,還好搞出一個(gè)稍微有點(diǎn)含金量的的提升,在這里得感謝我的大飛哥的鼎力支持!阿里嘎多。。。
該demo涉及的技術(shù)點(diǎn)(僅供參考):
element-ui
koa2
MongoDB
Solidity
go-ethereum
IPFS星際文件系統(tǒng)
web3
truffle
輔助鏈接及工具:
Solidity在線編譯
MateMask
源碼地址: https://github.com/Jacky-MYD/vue-dapp-demo
至于開發(fā)環(huán)境的搭建應(yīng)該是比較繁瑣的,上述鏈接可以參考,當(dāng)然各技術(shù)點(diǎn)的官網(wǎng)會(huì)好一點(diǎn)。
項(xiàng)目目錄

內(nèi)置客戶端(client)和服務(wù)端(server),可以download項(xiàng)目
啟動(dòng)項(xiàng)目:
1.啟動(dòng):MongoDB
sudo mongod
2.cd到服務(wù)端:
cd serve
npm install
npm run start // 默認(rèn)端口8081
3.cd到客戶端
cd client
npm install
npm run dev // 默認(rèn)端口:8090
4.打開Ganache,默認(rèn)本地環(huán)境:http://127.0.0.1:7545
5.登錄MateMask
6.啟動(dòng)ipfs環(huán)境
ipfs daemon
7.瀏覽器訪問:http://127.0.0.1:8090
在各種環(huán)境都啟動(dòng)好之后,就可以通過合約進(jìn)行注冊(cè)用戶
demo簡(jiǎn)介
在編寫好服務(wù)端register的API以及客戶端代碼后(這里就不解釋了),
編寫合約:
Account.sol
pragma solidity ^0.5.8;
import "./SafeMath.sol";//開源的安全操作unit256的合約
contract Account{
using SafeMath for uint256;
//新成員創(chuàng)建事件
event NewMember(string _name, string _avator);
//成員信息結(jié)構(gòu)
struct Member {
string name;//名字
string avatar;//頭像
bool isExist;//是否注冊(cè)
uint256 balance;//可周轉(zhuǎn)余額
}
//地址到成員信息的mapping
mapping(address => Member) internal addressToMember;
//限制調(diào)用的條件
modifier onlyMemberOf(address _from){
require(addressToMember[_from].isExist);
_;
}
// 注冊(cè)
function registerMember(string memory _name, string memory _avatar) public {
require(!isMemberOf());
addressToMember[msg.sender] = Member(_name, _avatar, true, 0);
emit NewMember(_name, _avatar);
}
...
}
通過truffle進(jìn)行合約編譯 ,編譯后會(huì)得一個(gè)Account.json文件,里面含有合約的ABI和合約地址等信息
const Account = artifacts.require("Account");
module.exports = function(deployer) {
deployer.deploy(Account);
};
連接web3
import Web3 from 'web3'
let getWeb3 = new Promise((resolve, rejects) => {
var web3js = window.web3;
var web3Provider;
if (typeof web3js !== 'undefined') {
web3Provider = web3js.currentProvider;
} else {
// If no injected web3 instance is detected, fall back to Ganache
web3Provider = new Web3.providers.HttpProvider('http://127.0.0.1:7545');
}
var web3 = new Web3(web3Provider);
resolve({
injectedWeb3: web3.eth.net.isListening(),
web3() {
return web3
}
})
}).then((result) => {
return new Promise(function (resolve, reject) {
result.web3().eth.net.getId((err, networkId) => {
if(err) {
reject(new Error('Unable to retrieve network ID'))
} else {
console.log('retrieve newworkId: ' + networkId)
result = Object.assign({}, result, {networkId})
resolve(result)
}
})
})
}).then(result => {
return new Promise(function (resolve, reject) {
result.web3().eth.getCoinbase((err, coinbase) => {
if(err) {
reject(new Error('Unable to retrieve coinbase'))
} else {
coinbase = result.web3().utils.toChecksumAddress(coinbase);
console.log('retrieve coinbase: '+ coinbase);
result = Object.assign({}, result, {coinbase});
resolve(result)
}})
})
});
export default getWeb3
通過web3調(diào)用合約中的方法
import Web3 from 'web3'
import { address, ABI } from './comtractsAbi/Account'
import AccountContract from '../../build/contracts/Account'
let getContract = new Promise((resolve, rejects) => {
let web3 = new Web3(window.web3.currentProvider)
let MyContract = new web3.eth.Contract(AccountContract.abi, AccountContract.networks[5777].address)
if (!MyContract) {
reject("no contract instance build")
}
resolve(MyContract);
})
export default getContract
配置ipfs
import ipfsAPI from 'ipfs-api'
import util from './util'
let ipfs = ipfsAPI('localhost', '5001', {protocol: 'http'})
let ipfsPublic = {
/**
* set ipfs
*/
add: (param) => {
return new Promise(async (resolve, reject) => {
const buffer = Buffer.from(param)
await ipfs.add(buffer).then( rsp => {
resolve(rsp[0].hash)
}).catch(err => {
console.error(err)
reject (err)
})
})
},
/**
* get ipfs buffer
*/
getBuff: (hash) => {
return new Promise(async (resolve, reject) => {
await ipfs.cat(hash).then( buff => {
resolve(buff)
})
.catch(err => {
console.error(err)
reject (err)
})
})
},
/**
* buffer to utf-8 str
*/
get: (hash) => {
return new Promise(async (resolve, reject) => {
await ipfs.cat(hash).then( buff => {
let strContent = util.Utf8ArrayToStr(buff);
resolve(strContent)
})
.catch(err => {
console.error(err)
reject (err)
})
})
}
}
export default ipfsPublic
至于代碼詳情,可看源碼
項(xiàng)目流程簡(jiǎn)單說明
在合約部署后,項(xiàng)目啟動(dòng)完成時(shí),會(huì)得到一個(gè)合約地址(address:"0x07f417017aa903616eecc7fb4932b7f1383305a3")

在點(diǎn)擊注冊(cè)后,注冊(cè)信息會(huì)存儲(chǔ)到ipfs中,ipfs將返回一個(gè)hash值('QmT1QLKwUkgsR2uR8XFxhyoVp3SRnJFyxqHvdPG1RicUS6'),用于獲取相應(yīng)的信息
獲取hash后,通過合約地址調(diào)用合約中的registerMember方法,然后會(huì)自動(dòng)打開MateMask,進(jìn)行一筆交易

交易完整后,就會(huì)產(chǎn)生一個(gè)block(塊),這個(gè)block中含有一些信息,如:調(diào)用者(address:"0xd0922930b70f81777458aa965482bf6f28ea840a"),交易hash(transactionHash: "0xeddcf41eb0b35004bdc95daaeb31708a2634cc577e1bf13f69c5506d3ea69215"),區(qū)塊高度(blockNumber:33)等

最后,我在這里將一些相應(yīng)的字段信息同步到MongoDB中。


更多細(xì)節(jié)內(nèi)容,可以運(yùn)用你所能運(yùn)用的手段學(xué)習(xí)。
Over!??!