區塊鍊大學營出品
參與 | Arvin、波波
由于Dapp(去中心化應用)涉及到智能合約概念、以太坊區塊鍊機制等更為基礎的知識點,僅從程式設計角度來講解Dapp開發的入門,不免給人以空中樓閣、鏡花水月的感受。是以,以太坊這份面向Dapp新手的開發教程,從去中心化應用最基礎的知識點開始,一步一步介紹如何用以太坊用戶端開發出一個最簡答的智能合約,也就是Dapp的後端代碼。
盡管這份Dapp開發入門教程成文已久,但它對于區塊鍊開發新手的友好程度,是後來的很多開發教程都無法比拟的。為此,區塊鍊大學營特地将其翻譯成中文,以飨讀者。Enjoy!
區塊鍊基礎
以太坊(Ethereum)創造的去中心化網絡,被稱為第三代網絡(‘網絡3’)。與第二代網絡(‘web2’)所不同的是,在以太坊網絡中沒有中心式的網絡伺服器,是以“沒有中間商拿差價”,沒有人能夠竊取你的資料或者将資料提供給美國國家安全局(National Security Agency,簡寫為NSA),當然也沒有分布式拒絕服務(Distributed Denial of Service,簡稱為DDoS)。
一個去中心化應用程式(Dapp)由兩部分組成:一個用HTML編寫的前端和一個後端(可以将其了解為前端的‘資料庫’)。
下面首先說個好消息:如果您對開發網站有一定了解,并且喜歡bootstrap或任何其他架構,您可以繼續使用它們,因為去中心化應用程式的前端跟現有網絡中的前端是一樣的,同樣可以被整個網絡通路,并且可以通路CDN。實際上,對于所有的設計意圖和使用目的,為去中心化應用程式編寫HTML開發前端與開發網站完全相同,并且從web 2轉換到web 3在很多情況下是非常簡單的。
還有個更好的消息:通過使用回調函數,你可以獲得反應式程式設計(這會讓使用angular、meteor和derby架構的粉絲非常高興),并且不用學習新的架構。
還有個甚至更好的消息:因為以太坊依靠密碼原理運作,是以每個去中心化應用程式都知道每個使用者的假身份。在去中心化的網絡中,使用者不需要‘建立賬戶’或‘登入’來通路你的去中心化應用程式,你可以認為這是web3的開放辨別。
其實沒有什麼壞消息,除了可能的來自現有網絡世界web2中的不良因素,比如與金錢或賭博網站進行不誠信交流、僞造随機數字資訊以牟利。在以太坊(Ethereum)網絡上,後端操作由網絡上的所有節點驗證,這意味着後端将始終執行其代碼所說的操作。這就是為什麼你可能會聽到人們說以太坊(Ethereum)是‘去權威’的原因--使用者不需要信任中央權威機構去‘做正确的事情’。
以太坊用戶端
本教程将重點介紹Alethzero用戶端的上手使用,以及如何用它建立簡單的智能合約 ,也就是去中心化應用的後端程式。
重要提示:本教程使用的Alethzero用戶端目前處于快速疊代期,最穩定的版本是您下載下傳的最新版。如果您想體驗最新版,可以随意切換到最新版的用戶端,但請注意,本教程尚未經過測試可以無縫地用于您将使用的最新版本。
我們将使用Alethzero,這是為開發人員設計的以太坊(Ethereum)網絡用戶端的C ++實作。需要強調的是,我們将安裝最新版,這是截止目前最穩定的,并包含所有最新功能的版本。
OSX和Windows平台上的可執行二進制檔案可以從這裡獲得 (https://github.com/ethereum/cpp-ethereum/wiki)。我們下面在Ubuntu平台上進行,其按照步驟請詳看此連結(https://github.com/ethereum/cpp-ethereum/wiki/Installing%20Clients)。
如果一切順利,在啟動Alethzero之後,您應該看到如下圖的内容,具體取決于您的平台和螢幕分辨率。
如果您的螢幕分辨率不同,并且并非所有界面都可見,請手動關閉顯示屏中的所有窗格,方法是單擊它們的“x”符号,直到它們全部消失,調整螢幕大小以适應您的分辨率,然後通過右鍵單擊來手動重新添加,添加按鈕位于标題欄下方(在“重新整理”按鈕的右側)。
我們首先介紹這個視圖。在螢幕的中心是一個浏覽器視窗,确切地說是一個Webkit視圖。您可以像浏覽任何其他浏覽器一樣浏覽現有的網頁,例如百度。
其餘面闆包含我們稍後将使用的調試和技術資訊。盡管對開發人員有用,但這不是一個非常友好的使用者界面,是以以太坊計劃開發最新版的浏覽器(暫定名為“Mist”),而且計劃建構在Go Ethereum實作之上,且具有完全不同的外觀和體驗。事實上,在以太坊更新其浏覽器後,其界面将像下面這樣:
以上是我們Amsterdam團隊正在開發的以太坊浏覽器“Mist”的一種可能的外觀概念,作為一個通路去中心化應用程式的商店。當體驗不佳時,請随時重新調整您的螢幕。您還可以将面闆拖放到彼此的頂部以堆疊它們。
選擇什麼
以太坊是一個通用的程式設計平台。您可以在上面建構遊戲,金融應用程式,賭博應用程式,保險公司,社交網絡,以及任何事情!但是,首先記住使用者的需求總是好事,你必須知道他們在集中式網絡應用中缺少什麼?
在現在這個教程中,我們将編寫一個簡單的智能合約(智能合約的功能有點像銀行,但是有一個全球可以審計的透明總帳)應用來發行通證。我們将發行10000個通證(token,用于代表一個價值實體),如果我們隻是自己持有這些通證肯定就不會有那麼多樂趣,是以我們還會建立一個方法以允許我們将它們發送給我們的朋友。
其實,我們就是在發行自己的貨币,雖然是以一種非常基本的方式,但本質上是這樣的。在web2世界中,我們可以用PHP和MySQL輕松地建構一個這樣的應用程式,但您的使用者必須相信您做好以下的所有事情:擁有誠實的會計師,分類帳保持一緻,政府沒有克扣資金,黑客不會闖入伺服器,員工在任何時候都是可靠的且沒有設定後門,程式員不會犯一個錯誤,還有許多許多......現在,你看出web3和web2的差別了吧。
智能合約
我們的後端(即以太坊網絡中的‘智能合約’)将使用一種名為Solidity的程式設計語言。當然,在建構以太坊網絡後端時,您可以使用其他幾種語言,包括LLL(類似于Lisp)和Serpent(類似于Python)。我們将使用 Solidity,因為它是ETHDEV團隊官方支援的語言。
正如我們上面提到的,我們正在建立一個小銀行,是以我們需要做兩件事:
- 執行個體化至少一個有帳号餘額的通證,以便支撐智能合約第一次建立時的啟用。
- 建構一個類似于contract.send(account,amount)的“發送”函數,來讓通證流動起來。
讓我們繼續深入,請随意打開您最喜愛的文本編輯器來編輯您的第一份智能合約代碼:
1contract metaCoin {
2 mapping (address => uint) balances;
3 function metaCoin() {
4 balances[msg.sender] = 10000;
5 }
6 function sendCoin(address receiver, uint amount) returns(bool sufficient) {
7 if (balances[msg.sender] < amount) return false;
8 balances[msg.sender] -= amount;
9 balances[receiver] += amount;
10 return true;
11 }
12}
不要驚慌,它比看起來簡單得多。智能合約由方法組成。第一種稱為metaCoin的方法是一種特殊的構造函數方法,用于定義智能合約資料存儲的初始狀态。構造函數的名稱始終與智能合約名稱相同。這個初始化代碼在建立智能合約時隻運作一次,而不會再次運作。智能合約的第二部分是智能合約代碼本身,永遠在以太坊網絡上存在的,永遠不變的内容,它将在數百萬節點上運作以確定它每次都能傳回預期的結果。在我們的例子中,這是一個簡單的函數,用于檢查發件人是否有足夠多的餘額,如果是,則将通證從一個帳戶轉移到另一個帳戶。
我們來看看更詳細的内容:
1mapping (address => uint) balances;
這一行建立一個存儲映射,您的代碼可以嚴格地将資訊寫入智能合約存儲,在這裡我們已經定義了一個類型為address和uint的鍵值對的映射,這個整體有個名字,餘額(balances)。這就是我們将存儲使用者通證餘額的地方(當然這些代碼需要執行在以太坊網絡上才能生效)。
請注意,我們已經指定了兩種資料類型,位址和uint。與Serpent不同,Solidity是靜态類型的,将在編譯時執行類型檢查。在編譯之前指定類型還允許我們減小事務傳遞的資料數組的大小,并允許編譯器建立更多優化的EVM代碼。
1 function metaCoin() {
2 balances[msg.sender] = 10000;
3 }
這是我們智能合約的初始化:它隻會運作一次(因為它在構造函數方法'metaCoin'中),它将做以下操作。首先,它使用msg.sender來查找交易發件人的公開位址;其次,它使用我們的映射通路我們的智能合約存儲的餘額(balances)。智能合約将資料存儲為長度為32個位元組的鍵值對。
msg.sender 是一個表示您公鑰的160位數字,這是一個以太坊網絡上的無法僞造的獨特辨別符,當然這得益于以太坊實作的加密法則。還有其他的事情,以太坊保證智能合約收到真實可靠的交易 -- 我們将在其他教程中探讨這些。
現在我們已經配置設定了一個初始餘額,接下來讓我們來看看'sendCoin'函數,這個函數在我們每次調用智能合約時執行。這是使用者可以調用的唯一可執行函數,而我們的初始化函數不能再次被調用。
1function sendCoin(address receiver, uint amount) returns(bool sufficient) {
2 if (balances[msg.sender] < amount) return false;
3 balances[msg.sender] -= amount;
4 balances[receiver] += amount;
5 return true;
6 }
這個函數有兩個傳遞給它的參數:receiver是代表接收者的另一個160位公共位址,amount 是你希望發送給接收者的通證數量。
在第一行中,我們将檢查msg.sender的目前餘額是否小于我們希望發送的通證的數量。如果是,我們将傳回空,并且不執行接下來的兩行代碼。這是合理的,因為調用智能合約的賬戶是發送令牌的賬戶,并且它必須有足夠多的通證來完成交易。
是以,為了将通證從一個存儲位址轉移到另一個存儲位址,傳遞給我們函數'transfer'的三個參數必須是:msg.sender,receiver和amount。
如果餘額足夠,條件評估将通過,接下來的兩行将減去發件人餘額發送的金額: balances[msg.sender] -= amount; ,然後添加到接收通證的帳戶餘額: balances[receiver] += amount; 。
是以現在我們有了進行通證流動的功能,将通證從一個賬戶的控制下轉移到另一個賬戶。
不要用光瓦斯!
在我們走得更遠之前,有一個重要的概念需要了解,它将幫助您進一步了解以太坊智能合約,它就是瓦斯(Gas)。
讓我們來看看下面的内容:為了給去中心化網絡提供動力,以太坊不可能依賴任何集中的權限(因為有權限意味着可以操縱資料庫)。相反,參與網絡的每個節點都擁一個資料庫副本,并獨立進行審計。
網絡節點在資料庫中處理正在執行的代碼,并通過表決就資料庫的正确狀态達成一緻。多數人總是赢得選票,并且節點被激勵來做這種驗證工作。投票通常每隔一段時間進行,平均每隔12.7秒進行一次投票。
我們之前編寫的智能合約将存儲在這個資料庫中。智能合約在使用者或其他智能合約調用時将被觸發執行。
如果您認為這種必要的方法在處理速度方面存在限制,那麼您是對的。以太坊網絡的總處理能力,無論其形成的節點數量如何,都等于1999年的一款智能手機。這意味着您不會希望在以太坊網絡上存儲上兆位元組的資料,或者渲染3d圖形。當然有一些解決方法,包括我們即将推出的存儲解決方案Swarm和我們的安全消息協定Whisper,這兩種配套技術都适用于以太坊。
這也意味着,因為計算能力是有限的,是以必須仔細衡量,以便沒有一個單獨的行為者能夠犯下邪惡的行為,例如在世界以太坊節點上運作無限循環。這個度量機關被稱為瓦斯(“Gas”)。
當你嘗試簽訂一份智能合約時,瓦斯會起作用。您可以調用智能合約的一個函數,然後執行該函數中的代碼。它可以驗證托管服務,可以為‘分布式社交應用程式’中的好友點贊,可以将一定數量的智能合約規定的通證傳輸給另一個使用者,等等。
為了執行這個功能,智能合約将需要瓦斯,就像你的汽車需要燃料一樣。是以,作為函數調用的一部分,您需要指定您想要發送給智能合約的瓦斯數量,以及您願意為該瓦斯支付多少費用(價格按以太币計算,這是以太坊的“燃料”和計費機關)。
智能合約可以支援的不同操作的價格是不同的。例如,一個執行循環耗費一個機關瓦斯。其他的,比如寫入存儲,成本要高得多(因為存儲是非常稀缺的資源)。如果您向智能合約中發送過多的瓦斯,但并未全部使用,以太坊會退還給您。如果發送得太少,智能合約将停止并復原(就像您的汽車在燃料不足時無法前進一樣)。
瓦斯的定價取決于社群的全球共識。是以,瓦斯報價最高的操作将首先在網絡上執行,稍後再運作其他低價操作。
上傳智能合約
現在您已經了解了以太坊的基本原理,并且您已經寫好了第一份智能合約,現在是時候将它部署到以太坊網絡上。
如果您尚未這樣做,請打開您的Alethzero用戶端,并熟悉該界面。確定你手邊已經打開了一個記事本,并編輯好前面講述的智能合約代碼。為了本教程的目的,您需要先斷開到Testnet的連接配接,然後從調試菜單中選擇“使用私有鍊”并建立您自己的私有鍊。這樣,當你開發你的去中心化應用時,你不依賴于線上測試。點選菜單欄中标記為“新交易”(“New Transaction”)的按鈕,彈出新的交易對話框。這是您輸入智能合約代碼和發送交易的地方,它包括發送交易的位址,瓦斯和瓦斯價格(gasPrice)的選項以及用于輸入智能合約代碼或交易資料的窗格。現在關閉它。正如前面提到的,儲存這份智能合約或者運作它需要瓦斯或者說以太币,但是目前我們隻有0個機關。為了獲得一點以太币,您需要參與投票過程,以保證分散資料庫的完整性,這個過程就是俗稱的“挖礦”。
在這種情況下,您沒有連接配接到網絡,因為您運作的是私有鍊,是以您隻能挖掘新塊。點選工具欄中的‘礦池’(Mine)-- 然後進入調試并選擇‘強制挖掘’(force mining)。您應該開始看到各種标簽資訊。采礦标簽頁有一個挖礦可視化界面 -- 當你成功挖到一個塊時,會出現紅色尖峰,這樣你的餘額就會增加。在這個過程中有一個有趣的标簽頁是區塊鍊(Blockchain)-- 這裡記錄着每一次投票并用一個數字進行标記。先賣個關子,待會我們會繼續講述相關内容。
一旦你是15000個以太币的持有者時,你可以驕傲地停止采礦。再次點選‘礦池’(Mine)來停止挖礦。現在讓我們部署我們的智能合約。
重新打開新交易彈窗,複制我們之前寫的智能合約代碼并粘貼在‘Data’文本框中。現在界面如下圖所示:
由于我們正在嘗試建立智能合約并且不會将以太币發送給其他帳戶,是以您可以安全地将所有字段保留為預設值。我們将以10 Szabo的價格标定每機關瓦斯來發送智能合約。Szabo是另一個價值機關,相當于0.000001以太币。由于我們的合同建立代碼非常簡單,是以我們将得到退還的大部分費用,因為智能合約的儲存不會消耗所有的瓦斯。
如果您有任何編譯錯誤,很可能是因為您沒有正确複制合約--如果調試器發現錯誤,它會為您提供相關的行和資訊。如果您已正确粘貼智能合約代碼,則會看到合約代碼下面的窗格中顯示的兩條消息。第一個标題為“Solidity”包含了看起來像JavaScript的代碼段的内容,其中包括智能合約中所有可執行函數的清單,最重要的是我們的函數‘sendCoin’(它充當ABI,應用程式位元組接口,即Application Byte Interface)。将這些資訊複制到記事本中,稍後您還需要它。第二條消息是類似于“PUSH2 0x27 0x10 CALLER ...”的類似彙編的指令。這是您的智能合約的EVM代碼,以編譯後的形式呈現。
現在您的智能合約已經編譯好了,您隻需按執行(‘Execute’)按鈕,即可在全球的去中心化資料庫中部署。由于您還沒有開采“礦石”,是以您的智能合約建立會落入“待處理”(Pending)狀态。“待處理”窗格視圖如下:
在您按下執行(‘Execute’)按鈕後,如果您檢視“待處理”(Pending)窗格中特定事務的‘create’字段,會有類似‘1f530b6b ...’的内容(當然,因為每個智能合約會建立一個唯一的ID,您的結果肯定和這個不一樣)。
現在您有一個“待處理”(Pending)智能合約,您需要通過挖掘一個塊來将這個事務送出到區塊鍊上(在一個實時網絡上,任何其他挖掘的人都将接收到這個事務,并試圖将其包含在挖掘到的塊中)。點選‘礦池’(Mine)按鈕進行挖礦,直到事務狀态從“待處理”(Pending)轉為“智能合約”(Contract)狀态。點選‘礦池’(Mine)按鈕再次關閉挖礦,并在智能合約窗格中單擊您的新合約。您将看到如下所示的内容:
您可以從智能合約“資料存儲”(data storage)中的一個條目中看到顯示了您的公共位址的SHA3鍵值和數字“10,000”。一切看起來不錯,現在我們可以認為,至少我們的構造函數已經正确運作。現在我們想測試一下我們是否可以将通證發送給另一個使用者的公共位址,為了運作我們的sendCoin功能,我們需要發送一個事務到合約位址,指定一個目的位址(‘to’指定的框),和一個數量(‘Value’),最重要的是交易資料數組中的一個函數ID。找到事務處理窗格并将合約位址粘貼到“位址”框中,結果如下:
現在在我們之前輸入代碼的區域中,我們首先将函數ID和收件人位址和值分别放在不同的行上。還記得前面的操作步驟中儲存的‘sendCoin’函數的ID嗎?我們使用0xec6d9353ca85eb80076817fa989f8825e136d55d(這是我的以太坊網絡位址)和任何低于10000的值。如下所示:
1$0x90b98a11
20xec6d9353ca85eb80076817fa989f8825e136d55d
3500
每次在智能合約中調用函數時,其格式都是這樣的:4位元組函數ID,後面跟着函數參數(整個資料會自動填充為32個位元組)。在後面的教程中你會看到更多的例子。
現在我們執行一個新的操作來重溫一下。首先點選執行,你應該再次看到一個待處理的事務,然後點選礦池,直到你生成一個新塊,然後停止挖掘。你的智能合約現在應該看起來像這樣:
寫在最後
圓滿完成!現在你的第一個智能合約就被建立出來了。如果你對它的效果感到滿意,就可以将智能合約上傳到測試鍊實際加以測試。
原文釋出時間為:2018年03月09日
本文作者:區塊鍊大學營
本文來源:
CSDN區塊鍊大學營,如需轉載請聯系原作者。