基于以太坊的去中心化宠物商店构建教程
2 月 4 日晚,百度悄然上線了區塊鏈游戲“萊茨狗”,pet-chain.baidu.com,造型和玩法上與“鏈養貓”如出一轍。官方介紹:“萊茨狗”的開發團隊來自百度金融區塊鏈實驗室,目前的技術已應用于多條核心業務線,支撐了超 500 億元資產的真實性問題。
針對寵物商店這一現象級游戲應用,我們給出了一個在以太坊上構建去中心化區塊鏈應用的教程。教程中使用了 Solidity 語言和 Truffle 框架,詳細說明了智能合約的編寫、編譯、模擬部署和測試過程,并介紹了如何使用 Truffle Box 構建應用的 UI。
大家都搞區塊鏈,來不及解釋了,趕緊上車就對了,按照這個教程自己寫個寵物商店吧。
更多干貨內容請關注微信公眾號“區塊鏈前哨”,(ID:blockchain-666)
基于區塊鏈構建的去中心化應用(Dapp,Distributed application)引人關注,因為這樣的應用并非集中于某個特定的管理者。
下面,我們將生成一個基本的去中心化應用,以此實際了解此類應用的機制。
遵循 Truffle 指南中提供的“以太坊寵物商店”,我將在 Web 上實際構建一個寵物商店去中心化應用。基于 Truffle 開發框架,我使用了一種稱為“Solidity”的語言編寫智能合約。
項目完工的效果如下圖。如果用戶點擊了心儀寵物所對應的“adopt”按鈕,應用將啟動 MetaMask 檢查所展示的寵物的數量和費用、創建交易并使用 ETH 支付。
我們可以看到,該應用不同于一般的電子商務網站,在購買時不必輸入個人信息或信用卡信息。此外,購買數據以交易形式記錄在以太坊區塊鏈中,因此不會被篡改。
實現去中心化應用的具體流程如下:
-
設置開發環境;
-
使用 Truffle Box 創建 Truffle 項目;
-
描述智能合約;
-
編譯并模擬部署(Migrating)智能合約;
-
測試智能合約;
-
建立附著于智能合約之上的 UI;
-
在瀏覽器中使用去中心化應用。
首先準備使用 node 和 npm 的環境。對于 Ubuntu 操作系統,安裝 Node.js 8.x 的操作命令為:
$ apt-get update$ curl -sL https://deb.nodesource.com/setup_8.x | bash -
$ apt-get install -y nodejs
第一步,我們需要安裝 Truffle。
$ npm install -g truffleTruffle 是一個以太坊開發框架。對于智能合約開發,Truffle 是一種非常有用的框架,可以高效地實現源代碼的編譯和部署。
第二步,建立一個名為“pet-shop-tutorial”的文件夾作為工作目錄。通常使用命令 truffle init 初始化工作目錄,并創建一個空目錄。但是在本文給出的教程中,是在一個預先準備好的項目“Truffle Box”手工中創建了這個目錄:
$ mkdir pet-shop-tutorial$ cd pet-shop-tutorial
$ truffle unbox pet-shop
第三步,在“pet-shop-tutorial”目錄中建立如下圖所列的文件和目錄:
實際使用的目錄和文件如下:
-
contracts 目錄:包含描述智能合約的 Solidity 源文件;
-
migrations 目錄:模擬部署(migration)系統,用于部署智能合約過程中。
-
test 目錄:目錄中為測試文件,使用 JavaScript 和 Solidity 編寫;
-
truffle.js:Truffle 配置文件。
其中,Solidity 是一種描述以太坊智能合約的編程語言。
下面,我將使用 Solidity 編寫智能合約。在所創建的 contracts 目錄中,建立一個名為“Adoption.sol”的文件,文件內容如下:
下面我依次介紹代碼的各個部分:
pragma solidity ^0.4.4;該語句指定了 Solidity 編譯器的版本信息。此外,Solidity 與 JavaScript 類似,需在代碼行結尾處添加分號“;”。
contract Adoption { ??? }這里定義了一個名為 Adoption 的合約,并在其中實現合約。
address[16] public adopters;這句話定義了一個名為 adopters 的狀態變量。鑒于 Solidity 是一種靜態語言,因此變量必須要定義類型。除了 string、uint 等通用數據類型之外,Solidity 還具有一種特有的數據類型 address。address 中包含賬戶的地址。
這里,定義了一個名為 adopters 的 address 數組,該變量具有 16 個地址。
此外,在 adopters 變量前指定了 public,即任何人都可以訪問合約。
在定義了以上變量之后,開始定義合約的方法。
function adopt(uint petId) public returns (uint) {require(petId >= 0 && petId <= 15);
adopters[petId] = msg.sender;
return petId;
}
根據 adopters 數組的長度,將整數類型變量 petId 的值設為 0 到 15(數組的索引值從 0 開始)。
代碼中使用 require() 函數設置 petId 的值為 0 到 15。
msg.sender 表示執行函數者(或智能合約)的地址。
這樣,語句 adopters [petId] = msg.sender; 將執行函數者的地址添加到 adopters 數組。
返回值在 petId 中。
上面定義的 adopt() 函數返回一個地址,因為 petId 是 adopters 數組的鍵值。
但是,鑒于每次重加載都需要做 16 次 API 調用,我使用下面定義的 getAdopters() 函數返回整個 adopters 數組:
function getAdopters() public returns (address[16]) {return adopters;
}
鑒于變量 adopters 已經定義,函數可以僅指定數據類型,并將返回值返回。
至此,我完成了對智能合約的描述。
總結一下,我創建了如下的 Adoption 合約:“共有 16 種寵物。如果用戶想領養一只寵物,就將用戶地址和該寵物 ID 綁定在一起”。
下面,我們將繼續編譯智能合約,并模擬部署。
編譯將以編程語言編寫的源代碼轉譯為機器可直接執行的機器語言。換句話說,本例中就是將 Solidity 語言編寫的代碼轉換為 EVM(以太坊虛擬機,Ethereum Virtual Machine)可執行的字節碼。
在包含去中心化應用的目錄中,使用終端等方式加載 Truffle Develop:
$ truffle develop然后,在啟動的 Truffle 開發控制臺上,輸入 compile 命令:
$ truffle(develop)> compile如果輸出如下,表明編譯成功。
Compiling ./contracts/Adoption.sol...Compiling ./contracts/Migrations.sol...
Writing artifacts to ./build/contracts
盡管其中可能存在一些公開可見的警告,但是繼續編譯是沒有問題的。下面請一直保持 Truffle 開發控制臺的運行。
模擬部署(Migration)類似于“移動”,就是將已有系統或類似系統遷移到一個新的平臺上。
在本例中,模擬部署文件完成將所創建的 Adoption 合約部署到以太坊區塊鏈網絡上。
如果查看 migrations 目錄的內容,其中已經存在一個名為“1_initial_migration.js”的 JavaScript 部署文件。該文件將 Migrations.sol 部署到 contracts 目錄中,并管理它,這使得一系列的智能合約可以正確地遷移。
下面在 migrations 目錄中創建一個名為“2_deploy_contracts.js”的部署文件。在部署文件中寫入如下內容:
const Adoption = artifacts.require("Adoption");module.exports = (deployer) => {
deployer.deploy(Adoption);
};
在前面打開的 Truffle 開發控制臺上,運行 migrate 命令:
$ truffle(develop)> migrate如果生成如下輸出,表明模擬部署成功完成:
測試智能合約是非常重要的一步。這是因為智能合約中的設計錯誤和缺陷將與用戶的代幣(資產)直接相關,可導致對用戶利益的嚴重損害。
智能合約測試主要分為手工測試和自動測試。下面分別介紹這兩種測試。
手工測試使用 Ganache 等本地開發環境工具,檢查應用的運行情況。這易于理解,因為這些工具實際指向 GUI 中的交易。
本文將跳過對手工測試的介紹。下面介紹自動測試。
在 Truffle 中,可使用 JavaScript 或 Solidity 描述智能合約的自動測試。在本例中,我采用 Solidity 編寫。
在所創建的 test 目錄中,創建一個名為“TestAdoption.sol”的文件,其中的內容如下:
文件內容略長。我將分解該文件做介紹。
首先,我導入了如下三個合約:
-
Assert.sol:測試期間的各種檢查工作。
-
DeployedAddresses.sol:獲取在測試期間部署的合約的地址。
-
Adoption.sol:測試智能合約。
創建一個名為“TestAdoption”的合約,并定義變量 adoption。adoption 包含 DeployedAddresses。
在下面給出的 TestAdoption 合約中,我定義了用于測試的函數:
function testUserCanAdoptPet() {uint returnedId = adoption.adopt(8);
uint expected = 8;
Assert.equal(returnedId, expected, "Adoption of pet ID 8 should be recorded.");
}
該代碼測試 Adoption 合約中定義的 adopt() 函數。如果 adopt() 函數功能正常,它將返回與參數具有同一數值的 petId(即返回值)。
此處將值為 8 的 petId 置入 adopt() 函數,并使用 Assert.equal() 函數確保與 petId 返回值匹配。
function testGetAdopterAddressByPetId() {address expected = this;
address adopter = adoption.adopters(8);
Assert.equal(adopter, expected, "Owner of pet ID 8 should be recorded.");
}
需要測試的是 petId 是否關聯了正確的所有者地址。代碼測試了寵物 ID 是 8 的所有者的地址是否正確。
順便提及,變量 this 表示的是當前合約的地址。
function testGetAdopterAddressByPetIdInArray() {address expected = this;
address[16] memory adopters = adoption.getAdopters();
Assert.equal(adopters[8], expected, "Owner of pet ID 8 should be recorded.");
}
最后,檢查具有所有地址的數組 adopters 是否被正確返回。
屬性 memory 并未保存在合約的“存儲”中,這意味著它是一個臨時記錄的值。
現在可以編寫測試。我將使用 Truffle Develop 返回測試文件。
$ truffle(develop)> test如果輸出如下,表明測試成功。
目前為止,我們已經完成了智能合約的創建,模擬部署在本地環境的測試區塊鏈中,并測試其是否正常工作。
下面,我們將創建用戶界面,在瀏覽器中實際查看寵物商店。
基本結構已經由 Truffle Box 構建,我們只需在以太坊中添加特性函數。
應用的前端部分位于 src 目錄中,我們需要編輯其中的 /src/js/app.js 文件。
下面給出 App 對象的聲明,我隨后在①到④處添加代碼。
下面分別介紹在① ~ ④處添加的源代碼。
① web3 實例化if (typeof web3 !== 'undefined') {App.web3Provider = web3.currentProvider;
} else {
App.web3Provider = new Web3.providers.HttpProvider('http://localhost:9545');
}
web3 = new Web3(App.web3Provider);
首先,確保 web3 的實例是“活動”的。如果它是“活動”的,那么使用所創建應用的 web3 對象替換它。如果它并非“活動”的,那么在本地開發環境中創建 web3 對象。
② 合約實例化鑒于我們現在可通過 web3 與“以太坊網絡”建立通訊,這時需要實例化所創建的“智能合約”。為實現合約的實例化,我們需要將合約的具體位置以及工作方式告知 web3。
$.getJSON('Adoption.json', function(data) {var AdoptionArtifact = data;
App.contracts.Adoption = TruffleContract(AdoptionArtifact);
App.contracts.Adoption.setProvider(App.web3Provider);
return App.markAdopted();
});
Truffle 提供了一個有用的軟件庫,稱為“truffle-contract”。該軟件庫作用于 web3 上,簡化了與“智能合約”的聯系。例如,truffle-contract 實現模擬部署期間合約信息的同步,無需手工更改部署地址。
Artifact 文件提供了部署地址和 ABI(應用二進制接口,Application Binary Interface)信息。
ABI 表示了合約接口上的信息,即變量、函數、參數等。
在 TruffleContract() 函數中插入 Artifact,并實例化合約。然后設置由 web3 實例化所創建的 App.web3Provider 到合約中。
此外,如果先前已經選定了寵物,那么這時需要調用 markAdopted()。每次智能合約數據發生改變時,都有必要對 UI 進行更新。更新 UI 定義為在③處給出的各種“函數”。
③ UI 更新下面的代碼確保寵物狀態保持更改,并且 UI 得到了更新。
var adoptionInstance;?App.contracts.Adoption.deployed().then(function(instance) {
adoptionInstance = instance;
return adoptionInstance.getAdopters.call();
?}).then(function(adopters) {
for (i = 0; i < adopters.length; i++) {
if (adopters[i] !== '0x0000000000000000000000000000000000000000') {
$('.panel-pet').eq(i).find('button').text('Success').attr('disabled', true);
}
}
?}).catch(function(err) {
console.log(err.message);
?});
代碼首先在所部署的 Adoption 合約實例上調用 getAdopters() 函數。call() 函數并不更改區塊鏈的狀態,它只是讀取數據,因此這里無需支付 GAS。
此后,代碼檢查是否每個 petId 都綁定了一個地址。如果地址存在,就將按鈕狀態改為“Success”,這樣用戶不能再次按下按鈕。
④ 操作 adopt() 函數var adoptionInstance;web3.eth.getAccounts(function(error, accounts) {
if (error) {
console.log(error);
}
var account = accounts[0];
App.contracts.Adoption.deployed().then(function(instance) {
adoptionInstance = instance;
return adoptionInstance.adopt(petId, {from: account});
}).then(function(result) {
return App.markAdopted();
}).catch(function(err) {
console.log(err.message);
});
});
在本例中,確認 web3 使用賬號無誤后,就實際進行交易處理。交易執行通過 adopt() 函數完成,輸入參數為一個包含 petId 和賬號地址的對象。
之后,使用在③中定義的 markAdopted() 函數,將交易結果在 UI 上以新數據顯示。
一旦萬事俱備,現在就可以在瀏覽器中查看上面創建的去中心化應用。
這里需要預先做一些安裝工作,因為我們將使用 Chorome 的一個擴展 MetaMask。賬號將通過下面給出的“錢包私鑰”(Wallet Seed),使用 Truffle Develop 的賬號。在執行 Truffle Develop 時,會顯示該私鑰(它是通用私鑰)。
candy maple cake sugar pudding cream honey rich smooth crumble sweet treat如果使用 MetaMask,可以通過菜單項“Lock”訪問如下的屏幕。
為了將 MetaMask 連接到 Truffle Develop 創建的區塊鏈,要將左上位置的“Main Network”改為“Custom RPC”,“Truffle Develop”更改為“http://localhost:9545”,并將顯示從“Main Network”更改為“Private Network”。
賬號由上面給出的私鑰生成,其中應該會具有少許的 100ETH,它們來自于合約部署中消費的 GAS 量。
一旦對 MetaMask 做了如上設置,就可以在終端等處輸入下面的命令,啟動本地 Web 服務器(鑒于已經 bs-config.json 和 package.json 已經創建,還可以使用 lite-server 軟件庫)。
$ npm run dev這樣,在瀏覽器中就能顯示如下的去中心化應用。
一旦點擊心儀寵物的“adopt”按鈕,交易就通過 MetaMask 發出,使用者可以用 ETH 支付寵物購買。
鑒于本文只是給出一個教程,因此內容主要聚焦于使用 Truffle Box 在以太坊中實現的去中心化應用的一些特性。即便讀者并不具備詳細的以太坊區塊鏈知識,只要能按教程實際動手操作,就可理解去中心化應用的工作機制。
原文發布時間為:2018-03-26
本文作者:分分鐘變大神
本文來源:微信公眾號-區塊鏈前哨,如需轉載請聯系原作者。
總結
以上是生活随笔為你收集整理的基于以太坊的去中心化宠物商店构建教程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 第六章,文本处理工具和正则表达式
- 下一篇: Java负数的位运算