嘿,程式設計師!手把手教你寫出智慧合約”Hello,World”

雪花又一年發表於2018-04-19

640?wx_fmt=jpeg&wxfrom=5&wx_lazy=1

區塊鏈大本營出品

參與 | 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之後,您應該看到如下圖的內容,具體取決於您的平臺和螢幕解析度。


640?wx_fmt=png


如果您的螢幕解析度不同,並且並非所有介面都可見,請手動關閉螢幕中的所有窗格,方法是單擊它們的“x”符號,直到它們全部消失,調整螢幕大小以適應您的解析度,然後通過右鍵單擊來手動重新新增,新增按鈕位於標題欄下方(在“重新整理”按鈕的右側)。


我們首先介紹這個檢視。在螢幕的中心是一個瀏覽器視窗,確切地說是一個Webkit檢視。您可以像瀏覽任何其他瀏覽器一樣瀏覽現有的網頁,例如百度。


其餘皮膚包含我們稍後將使用的除錯和技術資訊。儘管對開發人員有用,但這不是一個非常友好的使用者介面,因此以太坊計劃開發最新版的瀏覽器(暫定名為“Mist”),而且計劃構建在Go Ethereum實現之上,且具有完全不同的外觀和體驗。事實上,在以太坊更新其瀏覽器後,其介面將像下面這樣:


640?wx_fmt=png


以上是我們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’文字框中。現在介面如下圖所示:


640?wx_fmt=png


由於我們正在嘗試建立智慧合約並且不會將以太幣傳送給其他帳戶,因此您可以安全地將所有欄位保留為預設值。我們將以10 Szabo的價格標定每單位瓦斯來傳送智慧合約。Szabo是另一個價值單位,相當於0.000001以太幣。由於我們的合同建立程式碼非常簡單,因此我們將得到退還的大部分費用,因為智慧合約的儲存不會消耗所有的瓦斯。


如果您有任何編譯錯誤,很可能是因為您沒有正確複製合約–如果偵錯程式發現錯誤,它會為您提供相關的行和資訊。如果您已正確貼上智慧合約程式碼,則會看到合約程式碼下面的窗格中顯示的兩條訊息。第一個標題為“Solidity”包含了看起來像JavaScript的程式碼段的內容,其中包括智慧合約中所有可執行函式的列表,最重要的是我們的函式‘sendCoin’(它充當ABI,應用程式位元組介面,即Application Byte Interface)。將這些資訊複製到記事本中,稍後您還需要它。第二條訊息是類似於“PUSH2 0x27 0x10 CALLER …”的類似彙編的指令。這是您的智慧合約的EVM程式碼,以編譯後的形式呈現。


現在您的智慧合約已經編譯好了,您只需按執行(‘Execute’)按鈕,即可在全球的去中心化資料庫中部署。由於您還沒有開採“礦石”,因此您的智慧合約建立會落入“待處理”(Pending)狀態。“待處理”窗格檢視如下:


640?wx_fmt=png


在您按下執行(‘Execute’)按鈕後,如果您檢視“待處理”(Pending)窗格中特定事務的‘create’欄位,會有類似‘1f530b6b …’的內容(當然,因為每個智慧合約會建立一個唯一的ID,您的結果肯定和這個不一樣)。


現在您有一個“待處理”(Pending)智慧合約,您需要通過挖掘一個塊來將這個事務提交到區塊鏈上(在一個實時網路上,任何其他挖掘的人都將接收到這個事務,並試圖將其包含在挖掘到的塊中)。點選‘礦池’(Mine)按鈕進行挖礦,直到事務狀態從“待處理”(Pending)轉為“智慧合約”(Contract)狀態。點選‘礦池’(Mine)按鈕再次關閉挖礦,並在智慧合約窗格中單擊您的新合約。您將看到如下所示的內容:


640?wx_fmt=png


您可以從智慧合約“資料儲存”(data storage)中的一個條目中看到顯示了您的公共地址的SHA3鍵值和數字“10,000”。一切看起來不錯,現在我們可以認為,至少我們的建構函式已經正確執行。現在我們想測試一下我們是否可以將通證傳送給另一個使用者的公共地址,為了執行我們的sendCoin功能,我們需要傳送一個事務到合約地址,指定一個目的地址(‘to’指定的框),和一個數量(‘Value’),最重要的是交易資料陣列中的一個函式ID。找到事務處理窗格並將合約地址貼上到“地址”框中,結果如下:


640?wx_fmt=png


現在在我們之前輸入程式碼的區域中,我們首先將函式ID和收件人地址和值分別放在不同的行上。還記得前面的操作步驟中儲存的‘sendCoin’函式的ID嗎?我們使用0xec6d9353ca85eb80076817fa989f8825e136d55d(這是我的以太坊網路地址)和任何低於10000的值。如下所示:



1$0x90b98a11
20xec6d9353ca85eb80076817fa989f8825e136d55d
3500


每次在智慧合約中呼叫函式時,其格式都是這樣的:4位元組函式ID,後面跟著函式引數(整個資料會自動填充為32個位元組)。在後面的教程中你會看到更多的例子。


現在我們執行一個新的操作來重溫一下。首先點選執行,你應該再次看到一個待處理的事務,然後點選礦池,直到你生成一個新塊,然後停止挖掘。你的智慧合約現在應該看起來像這樣:


640?wx_fmt=png

寫在最後

圓滿完成!現在你的第一個智慧合約就被建立出來了。如果你對它的效果感到滿意,就可以將智慧合約上傳到測試鏈實際加以測試。

原文釋出時間為:2018年03月09日
本文作者:區塊鏈大本營
本文來源:CSDN區塊鏈大本營,如需轉載請聯絡原作者。


相關文章