了解DApp開發程序
- DApp是什么
- DApp的開發準備
- 環境
- 編程語言
- 智能合約
- 業務邏輯
- DApp原理
- 部署
- 呼叫
DApp是什么
DApp( Decentralized Application )即分布式應用或去中心化應用,DApp就是智能合約+App,
一個真正的DApp應用,需要同時滿足以下幾個條件:
- 應用必須完全開源、自治,且沒有一個物體控制該應用超過51%的- Token,該應用必須能夠根據用戶的反饋及技術要求進行升級,且應用升級必須由大部分用戶達成共識之后方可進行;
- 應用的資料必須加密后存盤在公開的區塊鏈上;
- 應用必須擁有Token機制,礦工或應用維護節點需得到代幣獎勵;
- 應用代幣的產生必須依據標準的加密演算法,有價值的節點可以根據該演算法獲取應用的代幣獎勵,
DApp的開發準備
環境
-
Remix,這是一個強大的IDE環境,不僅可以支持Solidity語法高亮和提示,還可以部署合約,呼叫和除錯合約,你甚至可以不必設定區塊鏈資料源,因為其內嵌了一個模擬區塊鏈的虛擬機叫JavaScript VM,使用教程點這里
-
以太坊私鏈,也就是搭建屬于自己的區塊鏈,最常見的方式就是通過Geth(Go-Ethereum)搭建了,他可以算是比較真實的區塊鏈平臺了,唯一區別就是不需要挖礦,也就是不需要共識,Geth搭建私鏈時,我們需要配置創世塊、bootnode、啟動節點、挖礦等操作,搭建私鏈教程可點擊此處,
-
測驗環境中的公鏈,一些組織為了讓開發者更方便的開發DApp,搭建了自己的以太坊平臺并對外開放,這些測驗平臺的以太幣可以免費獲取,但每個賬戶獲取的數量有限,不過也足以我們用來測驗了,在下文的實踐中用的也是這種方案,而測驗平臺有哪些呢,在我們安裝了MetaMask插件以后,可以在里面找到,如下圖所示,

-
以太坊,最后的環境肯定是以太坊了,不過我們在上線前一定要做好測驗,因為區塊鏈具有不可篡改性,我們的DApp在上線后出bug可是無法修復的,只能通過發布一個新的DApp,然后通知你的用戶以后使用新地址,所以我們在設計合約時應當設定有無效標志位,盡早地告知呼叫者該合約已經廢棄,
編程語言
撰寫一個DApp可以說是包括兩部分,合約部分和業務邏輯部分,
智能合約
Solidity,類JavaScript,這是以太坊推薦的語言,也是最流行的智能合約語言,具體用法參考http://solidity.readthedocs.io/en/latest/ ,本文所有合約都使用該語言撰寫,另外測驗、除錯Solidity有一個非常好的在線IDE–Remix ,由以太坊團隊推出的,由于考慮在線網路比較慢,可以使用本地IDE,使用教程點這里,
業務邏輯
業務邏輯部分即提供客戶端與智能合約互動的介面,相當于目前BS結構中的后臺邏輯,因此業務邏輯部分可部署在中心服務器中,而且在以太坊中每個智能合約函式的每一行代碼都有固定的gas費用以及延時的,一些簡單的邏輯應該交由業務邏輯處理,撰寫業務邏輯目前提供有以下幾種語言:
- JavaScript,主要是基于Web3.js這個庫呼叫智能合約,本文例子也是使用JavaScript撰寫的,
- Go,上述提到的以太坊私鏈搭建工具geth就是使用Go撰寫的,
- Python
- Java
- Ruby
- Haskell
- Rust
DApp原理
一個DApp被呼叫之前需要先部署到以太坊上,不管是私鏈,公鏈還是聯盟鏈,故本章節分為兩部分,DApp部署原理和呼叫原理,
部署
一個DApp由多個智能合約組成,部署一個DApp也就是同時部署多個智能合約,這里講述一下部署一個智能合約的流程,如下圖所示,
- 將撰寫好的Solidity智能合約通過RPC呼叫以太坊錢包或Web3.js等工具,
Web3.js發送合約原始碼到部署在以太坊節點的Solc編譯器, - 編譯器回傳合約位元組碼,
- 發送合約位元組碼和初始化引數到以太坊節點,
- 以太坊節點上EVM驗證完成后,部署到全網的所有節點,完成后回傳合約地址和應用二進制介面(ABI),
這里推薦使用Remix進行部署,因為Remix不僅可以連接瀏覽器內嵌的以太坊VM,還可以和MetaMask聯動,使用MetaMask當前所連的以太坊網路,而且Remix還可以除錯部署好的合約,十分方便,在Remix上部署十分簡單,選擇部署的以太坊網路和填好合約初始化引數后,點擊create按鈕即可,如果我們選的是MetaMask當前的以太坊網路,則會跳轉交易界面,因為部署合約本質上也是一筆交易,我們需要付交易手續費,如下圖所示,

部署后的合約其實外部還不能呼叫,還需要我們上傳源代碼進行驗證,不然別人不可能在不清楚原始碼情況下向合約發起交易,向你轉賬,如下所示,
呼叫
部署好的合約我們就可以呼叫了,根據呼叫方式的不同,本文分為前端呼叫和后端呼叫,
前端呼叫相對來說簡單一點,因為有MetaMask這個強大的插件,我們不必操心以太坊資料源,直接呼叫web3.currentProvider即可,下圖展示了前端呼叫合約的一般流程,由于前端連接的Web3 Provider是與特定的以太坊節點相連,前端不需要管方法的簽名,只需無腦呼叫合約中的方法即可,
至于后臺呼叫就麻煩一點了,由于后臺沒有MetaMask這么方便的工具可呼叫,因此要是呼叫公鏈上的智能合約,只能使用特定賬戶的私鑰簽名方法后,并且以該賬戶的身份呼叫合約,流程如下圖所示,
以太坊Web3.js提供呼叫合約的方法一共有四種:
- call: 這是最簡單的呼叫方式,適用于呼叫只讀的方法,也就是呼叫程序不會修改區塊鏈上的資料,因為它只讀取本地資料即可,因此不會消耗gas,而且可以立刻獲得回傳值,適用于前端呼叫,具體例子如下,
//合約宣告
contract test {
function multiply(uint a) returns(uint d) {
return a * 7;
}
}
//合約呼叫
var Multiply7 = eth.contract(contract.info.abiDefinition);
var myMultiply7 = Multiply7.at(address);
myMultiply7.multiply.call(3)
- sendTransaction: 可呼叫讀或寫方法,呼叫程序會創建一個交易,呼叫之后會回傳一個交易hash值,它會廣播到網路,等待礦工打包, 它會消耗gas,而且該呼叫不能立刻獲得回傳值,只能從event log中獲取,也是適用于前端呼叫,代碼如下,
wheelOfFortune.makeBet.sendTransaction(num - 1, betCount, tips, { from: web3.eth.accounts[0], value: betUnit \* betCount + tips }).then(function (result) {
if (result.logs.length > 0) {
var eventobj = result.logs[0].args;
$.ajax({
url: '/Wheel/makeBet/' + eventobj.pieceIdx + '/' + betCount + '/' + tips + '/' + web3.eth.accounts[0],
success: function (data) {
var nextRound = JSON.parse(data);
$("#currentTotal").text(nextRound.betPool.toLocaleString());
playersNumberOfPiece = nextRound.playersNumberOfPiece;
alert('下注成功');
}
});
}
});
- 直接呼叫: 這是一種特殊呼叫,可以說是前兩種呼叫的結合,因為當合約方法有constant修飾時,直接呼叫會等同于call,否則等同于sendTransaction,
var winIdx = (Math.random() \* wheel.config.pieceCount) >> 0;
// 后臺呼叫infura部署的合約必須用sendRawTransaction
var coder = require('web3/lib/solidity/coder');
var CryptoJS = require('crypto-js');
var Tx = require('ethereumjs-tx');
var privateKey = new Buffer("71112e795325d5cbf14d665091ce4626f26c8342b8038f1adcdfff26be04a220", 'hex');
var functionName = 'finishRound';
var types = ['uint'];
var args = [winIdx];
var fullName = functionName + '(' + types.join() + ')';
var signature = CryptoJS.SHA3(fullName, { outputLength: 256 }).toString(CryptoJS.enc.Hex).slice(0, 8);
var dataHex = signature + coder.encodeParams(types, args);
var data = '0x' + dataHex;
var account = "0x4BEB9EA54fc912B619D5C682BA1cB3524bc80955";
var nonce = web3.toHex(web3.eth.getTransactionCount(account));
var gasPrice = web3.toHex(web3.eth.gasPrice);
var gasLimitHex = web3.toHex(3000000);
var rawTx = { 'nonce': nonce, 'gasPrice': gasPrice, 'gasLimit': gasLimitHex, 'from': account, 'to': contractAddress, 'data': data }
var tx = new Tx(rawTx)
tx.sign(privateKey)
var serializedTx = '0x' + tx.serialize().toString('hex')
web3.eth.sendRawTransaction(serializedTx, function (err, txHash) {
if (!err) {
console.log(JSON.stringify({ "transactionHash": txHash }));
} else {
console.log("finish round error " + err);
}
});
- sendRawTransaction: 前兩種方法都不需要呼叫者提供交易發起者的私鑰進行方法簽名,因為MetaMask或本地以太坊節點提供了,但是當我們沒有MetaMask時呼叫公鏈合約,我們只能呼叫sendRawTransaction使用指定賬戶的私鑰簽名方法后才能呼叫合約,值得注意的是,該方法我們無法獲得回傳值,即使在event log中也拿不到,只能在得到transaction的hash后再讀取區塊鏈資訊才可以,一般在后臺呼叫方法時用到,代碼如下,
呼叫時需要注意的幾點:
當呼叫者給予Gas不足時,EVM會報出out of gas的錯誤,這時候會回滾本地交易所做過的所有修改,好在以太坊還提供了estimategas方法,可以讓我們在呼叫之前預估交易所需的Gas,因為Solc編譯器會算出每一句代碼的價格,不過有時會不準確,特別是出現死回圈或者違反了修飾方法的限制條件時,
呼叫頻率不能過快,一方面所有呼叫方法都是異步的,回傳時間可能會較長,另一方面有可能第一次呼叫的transaction還沒被挖到區塊中,下一次呼叫就來了,而且兩次呼叫的hash可能是一樣的,所以就會報replacement transaction underpriced錯誤,
當我們呼叫了不存在的方法時,EVM會自動呼叫合約中的Fallback方法作為兜底,而且會將Gas全耗完,如果沒有定義Fallback方法,才會報錯回滾,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/291705.html
標籤:區塊鏈
